基于springboot和ftp实现的网盘文件系统

基于springboot和ftp实现的网盘文件系统 1,项目简介 因为开发中很多时候都需要上传和下载文件,所以想开发出一个模块,用于文件的上传和下载,自然而然也就想到了网盘

本文包含相关资料包-----> 点击直达获取<-------

基于springboot和ftp实现的网盘文件系统

1.项目简介

因为开发中很多时候都需要上传和下载文件,所以想开发出一个模块,用于文件的上传和下载,自然而然也就想到了网盘,因为是个人开发,所以版本项目应该会持续迭代,优化,此外,技术栈是springboot+mybatis+jquery+bootstrap。

1.1 项目主要功能

  • 用户的邮箱注册、验证码验证以及用户登录

  • 引入QQ第三方登录,为用户提供便捷的登录通道

  • 不需要注册账号,也可以上传满足条件的临时文件,但是只4小时内有效

  • 文件的管理,上传、下载、重命名、删除、查看统计数据、分类管理等

  • 文件夹的管理,创建、删除、重命名

  • 文件的分享,支持通过链接和二维码的分享方式

  • 区分普通用户和管理员的角色,管理员可以修改普通用户的使用权限和网盘容量

1.2 技术栈

  • 前端
  • HTML、CSS、JavaScript、JQuery
  • BootStrap以及多个插件

  • 后端

  • SpringBoot + MyBatis
  • EhCache缓存
  • ThymeLeaf 模板引擎
  • 腾讯QQ 第三方登录
  • Ftp工具类、二维码工具类

部署 - 阿里云轻量应用服务器 - Docker 环境 - FTP 服务 - MySQL 数据库

1.3 部署注意

拉取项目到本地后,你需要修改一下配置信息

  • application.yml :修改数据源信息以及邮箱服务端信息

  • config.DruidConfig :修改druid登录的用户名和密码

  • utils.FtpUtil :修改FTP服务器的基本信息

  • utils.MailUtils :修改邮箱服务端发送方的邮箱

  • resources.qqconnectconfig.properties :修改 app_ID app_KEY redirect_URI

2.数据库设计

2.1 表结构

用户表

临时文件表

文件表

文件仓库

文件夹

2.2 E-R图

2.3 SQL插入

``sql DROP TABLE IF EXISTS file_folder ; CREATE TABLE file_folder ( file_folder_id int(11) NOT NULL AUTO_INCREMENT COMMENT '文件夹ID', file_folder_name varchar(255) DEFAULT NULL COMMENT '文件夹名称', parent_folder_id int(11) DEFAULT '0' COMMENT '父文件夹ID', file_store_id int(11) DEFAULT NULL COMMENT '所属文件仓库ID', time datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY ( file_folder_id`) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;


-- Table structure for file_store


DROP TABLE IF EXISTS file_store ; CREATE TABLE file_store ( file_store_id int(11) NOT NULL AUTO_INCREMENT COMMENT '文件仓库ID', user_id int(11) DEFAULT NULL COMMENT '主人ID', current_size int(11) DEFAULT '0' COMMENT '当前容量(单位KB)', max_size int(11) DEFAULT '1048576' COMMENT '最大容量(单位KB)', permission int(11) DEFAULT '0' COMMENT '仓库权限,0可上传下载、1不允许上传可以下载、2不可以上传下载', PRIMARY KEY ( file_store_id ) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;


-- Table structure for my_file


DROP TABLE IF EXISTS my_file ; CREATE TABLE my_file ( my_file_id int(11) NOT NULL AUTO_INCREMENT COMMENT '文件ID', my_file_name varchar(255) DEFAULT NULL COMMENT '文件名', file_store_id int(11) DEFAULT NULL COMMENT '文件仓库ID', my_file_path varchar(255) DEFAULT '/' COMMENT '文件存储路径', download_time int(11) DEFAULT '0' COMMENT '下载次数', upload_time datetime DEFAULT NULL COMMENT '上传时间', parent_folder_id int(11) DEFAULT NULL COMMENT '父文件夹ID', size int(11) DEFAULT NULL COMMENT '文件大小', type int(11) DEFAULT NULL COMMENT '文件类型', postfix varchar(255) DEFAULT NULL COMMENT '文件后缀', PRIMARY KEY ( my_file_id ) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;


-- Table structure for temp_file


DROP TABLE IF EXISTS temp_file ; CREATE TABLE temp_file ( file_id int(11) NOT NULL AUTO_INCREMENT COMMENT '临时文件ID', file_name varchar(255) DEFAULT NULL COMMENT '文件名', size varchar(255) DEFAULT NULL COMMENT '文件大小', upload_time datetime DEFAULT NULL COMMENT '上传时间:4小时后删除', file_path varchar(255) DEFAULT NULL COMMENT '文件在FTP上的存放路径', PRIMARY KEY ( file_id ) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;


-- Table structure for user


DROP TABLE IF EXISTS user ; CREATE TABLE user ( user_id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', open_id varchar(255) DEFAULT NULL COMMENT '用户的openid', file_store_id int(11) DEFAULT NULL COMMENT '文件仓库ID', user_name varchar(50) DEFAULT NULL COMMENT '用户名', email varchar(50) DEFAULT ' 0000@qq.com' COMMENT '用户邮箱', password varchar(20) DEFAULT NULL COMMENT '密码', register_time datetime DEFAULT NULL COMMENT '注册时间', image_path varchar(255) DEFAULT '' COMMENT '头像地址', role int(11) DEFAULT '1' COMMENT '用户角色,0管理员,1普通用户', PRIMARY KEY ( user_id ) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

```

3.项目开发

3.1 restful接口(部分源码)

```java / * @Description 上传临时文件 * @Author xw * @Date 23:14 2020/3/9 * @Param [files] * @return void / @PostMapping("/uploadTempFile") public String uploadTempFile(@RequestParam("file") MultipartFile file,String url) { session.setAttribute("imgPath","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2654852821,3851565636&fm=26&gp=0.jpg"); String name = file.getOriginalFilename().replaceAll(" ",""); if (!checkTarget(name)){ logger.error("临时文件上传失败!文件名不符合规范..."); session.setAttribute("msg", "上传失败!文件名不符合规范"); return "redirect:/temp-file"; } SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); String dateStr = format.format(new Date()); String path = "temp/"+dateStr +"/"+UUID.randomUUID(); try { if (FtpUtil.uploadFile("/"+path, name, file.getInputStream())){ //上传成功 logger.info("临时文件上传成功!"+name); String size = String.valueOf(file.getSize()); TempFile tempFile = TempFile.builder().fileName(name).filePath(path).size(size).uploadTime(new Date()).build(); if (tempFileService.insert(tempFile)) { try { String id = UUID.randomUUID().toString(); String p = request.getSession().getServletContext().getRealPath("/user_img/"); Long t = tempFile.getUploadTime().getTime(); url = url+"/file/share?t="+ UUID.randomUUID().toString().substring(0,10) +"&f="+tempFile.getFileId()+"&p="+size+"&flag=2"; File targetFile = new File(p, ""); if (!targetFile.exists()) { targetFile.mkdirs(); } File f = new File(p, id + ".jpg"); if (!f.exists()){ //文件不存在,开始生成二维码并保存文件 OutputStream os = new FileOutputStream(f); QRCodeUtil.encode(url, "/static/img/logo.png", os, true); os.close(); } //异步删除临时文件 tempFileService.deleteById(tempFile.getFileId()); session.setAttribute("imgPath","user_img/"+id+".jpg"); session.setAttribute("url",url); session.setAttribute("msg","上传成功,扫码/访问链接 即可下载!"); return "redirect:/temp-file"; } catch (Exception e) { e.printStackTrace(); } }else { logger.info("临时文件数据库写入失败!"+name); session.setAttribute("url","error"); session.setAttribute("msg", "服务器出错了,临时文件上传失败!"); } }else{ //上传失败 logger.info("临时文件上传失败!"+name); session.setAttribute("url","error"); session.setAttribute("msg", "服务器出错了,上传失败!"); } } catch (IOException e) { e.printStackTrace(); } return "redirect:/temp-file"; }

/ * @Description 网盘的文件上传 * @Author xw * @Date 23:10 2020/2/10 * @Param [files] * @return java.util.Map / @PostMapping("/uploadFile") @ResponseBody public Map uploadFile(@RequestParam("file") MultipartFile files) { Map map = new HashMap<>(); if (fileStoreService.getFileStoreByUserId(loginUser.getUserId()).getPermission() != 0){ logger.error("用户没有上传文件的权限!上传失败..."); map.put("code", 499); return map; } FileStore store = fileStoreService.getFileStoreByUserId(loginUser.getUserId()); Integer folderId = Integer.valueOf(request.getHeader("id")); String name = files.getOriginalFilename().replaceAll(" ",""); //获取当前目录下的所有文件,用来判断是否已经存在 List myFiles = null; if (folderId == 0){ //当前目录为根目录 myFiles = myFileService.getRootFilesByFileStoreId(loginUser.getFileStoreId()); }else { //当前目录为其他目录 myFiles = myFileService.getFilesByParentFolderId(folderId); } for (int i = 0; i < myFiles.size(); i++) { if ((myFiles.get(i).getMyFileName()+myFiles.get(i).getPostfix()).equals(name)){ logger.error("当前文件已存在!上传失败..."); map.put("code", 501); return map; } } SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); String dateStr = format.format(new Date()); String path = loginUser.getUserId()+"/"+dateStr +"/"+folderId; if (!checkTarget(name)){ logger.error("上传失败!文件名不符合规范..."); map.put("code", 502); return map; } Integer sizeInt = Math.toIntExact(files.getSize() / 1024); //是否仓库放不下该文件 if(store.getCurrentSize()+sizeInt > store.getMaxSize()){ logger.error("上传失败!仓库已满。"); map.put("code", 503); return map; } //处理文件大小 String size = String.valueOf(files.getSize()/1024.0); int indexDot = size.lastIndexOf("."); size = size.substring(0,indexDot); int index = name.lastIndexOf("."); String tempName = name; String postfix = ""; int type = 4; if (index!=-1){ tempName = name.substring(index); name = name.substring(0,index); //获得文件类型 type = getType(tempName.toLowerCase()); postfix = tempName.toLowerCase(); } try { //提交到FTP服务器 boolean b = FtpUtil.uploadFile("/"+path, name + postfix, files.getInputStream()); if (b){ //上传成功 logger.info("文件上传成功!"+files.getOriginalFilename()); //向数据库文件表写入数据 myFileService.addFileByFileStoreId( MyFile.builder() .myFileName(name).fileStoreId(loginUser.getFileStoreId()).myFilePath(path) .downloadTime(0).uploadTime(new Date()).parentFolderId(folderId). size(Integer.valueOf(size)).type(type).postfix(postfix).build()); //更新仓库表的当前大小 fileStoreService.addSize(store.getFileStoreId(),Integer.valueOf(size)); try { Thread.sleep(5000); map.put("code", 200); } catch (InterruptedException e) { e.printStackTrace(); } }else{ logger.error("文件上传失败!"+files.getOriginalFilename()); map.put("code", 504); } } catch (IOException e) { e.printStackTrace(); } return map; } ```

3.2 FileService文件服务接口

```java public class FileFolderServiceImpl extends BaseService implements FileFolderService {

/**
 * @Description 根据文件夹的id删除文件夹
 * @Author xw
 * @Date 2020/2/9 16:38
 * @Param [fileFolderId] 文件夹的id
 * @Return java.lang.Integer
 */
@Override
public Integer deleteFileFolderById(Integer fileFolderId) {
    return fileFolderMapper.deleteFileFolderById(fileFolderId);
}

/**
 * @Description 增加文件夹
 * @Author xw
 * @Date 2020/2/9 16:37
 * @Param [fileFolder] 文件夹对象
 * @Return java.lang.Integer
 */
@Override
public Integer addFileFolder(FileFolder fileFolder) {
    return fileFolderMapper.addFileFolder(fileFolder);
}

/**
 * @Description 根据文件夹的id获取文件下的文件
 * @Author xw
 * @Date 2020/2/9 16:34
 * @Param [fileFolderId] 文件夹id
 * @Return com.molihub.entity.FileFolder
 */
@Override
public List<MyFile> getFileFolderById(Integer fileFolderId) {
    return fileFolderMapper.getFileByFileFolder(fileFolderId);
}

/**
 * @Description 根据父文件夹获得所有的文件夹
 * @Author xw
 * @Date 2020/2/9 22:07
 * @Param [parentFolderId]
 * @Return java.util.List<com.molihub.entity.FileFolder>
 */
@Override
public Integer updateFileFolderById(FileFolder fileFolder) {
    return fileFolderMapper.updateFileFolderById(fileFolder);
}

/**
 * @Description 根据文件夹的id获取文件夹
 * @Author xw
 * @Date 2020/2/9 22:23
 * @Param [fileFolderId]
 * @Return com.molihub.entity.FileFolder
 */
@Override
public List<FileFolder> getFileFolderByParentFolderId(Integer parentFolderId) {
    return fileFolderMapper.getFileFolderByParentFolderId(parentFolderId);
}

/**
 * @Description 根据仓库Id获得仓库根目录下的所有文件夹
 * @Author xw
 * @Date 23:46 2020/2/9
 * @Param [fileStoreId]
 * @return java.util.List<com.molihub.entity.FileFolder>
 **/
@Override
public FileFolder getFileFolderByFileFolderId(Integer fileFolderId) {
    return fileFolderMapper.getFileFolderById(fileFolderId);
}

```

4.项目展示

主页

饼状图分析

菜单栏

我的图像

5.总结

这次花了四五天时间开发这个第一版网盘,考虑下次迭代将站内资源模块引入,然后可以接入各种资源模块,同时优化界面,并且实现offce文档的预览。代码届时会上传至github,以上就是个人网盘的开发流程。

参考文献

  • 基于OAuth2.0协议的企业分布式授权系统设计与实现(华中科技大学·支猛)
  • 办公文档管理系统设计与实现(电子科技大学·潘攀)
  • 基于Hadoop的分布式数据存储设计与实现(吉林大学·毛剑)
  • 基于微服务的可信文件存储系统的设计与实现(华中科技大学·吴景琰)
  • 基于SeaweedFS的分布式文件管理系统的设计与实现(南京大学·管登荣)
  • 基于Hadoop的分布式文件系统技术分析及应用(武汉理工大学·郝向涛)
  • 基于Hadoop的分布式数据存储设计与实现(吉林大学·毛剑)
  • 基于SSH资源管理系统的设计及实现(西安电子科技大学·杨静涛)
  • 一个分布式云存储系统的设计与实现(华中科技大学·何诚)
  • 基于分布式存储的云网盘系统的设计与实现(电子科技大学·王雨倩)
  • 基于OAuth2.0协议的企业分布式授权系统设计与实现(华中科技大学·支猛)
  • 基于SeaweedFS的分布式文件管理系统的设计与实现(南京大学·管登荣)
  • 基于Struts+Hibernate+Spring框架的Web应用与实现(武汉理工大学·甘森林)
  • 基于Hadoop的分布式数据存储设计与实现(吉林大学·毛剑)
  • 一种基于HDFS的高性能文件存储与管理系统(广东工业大学·张兴斌)

本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:源码港湾 ,原文地址:https://bishedaima.com/yuanma/35558.html

相关推荐

发表回复

登录后才能评论