赞
踩
项目编号:BS-XX-094
## 功能介绍
1. 多文件格式分类查看
2. 支持网格、表格视图、时间线三种展示视图
3. 支持极速秒传功能,提高上传效率
4. 多人上传同一文件,可多人并行上传,共享他人上传进度,极大提高上传效率
5. 拒绝冗余,每份文件只存一份,提高硬盘使用效率
6. 上传文件前台实时显示上传文件进度,上传速率,百分比等信息
7. 安全的下载机制,断点下载,权限校验,他人拿到了下载地址也无法下载您的文件
8. 支持视频音频播放,进度条拖拽,倍速播放
9. 拥有回收站功能,妈妈再也不怕我误删数据了
10. 高效的垃圾回收机制
## 软件架构
该项目采用前后端分离的方式进行开发和部署,主要用到以下关键技术
**前端**:Element UI、Vue CLI@3、Node.js、Webpack
**后台**:Spring Boot、Spring Data Jpa、Spring Security
**数据库** : MySQL或H2
**数据结构**:递归算法,树的遍历和插入...
下面展示一下系统部分功能:
用户登陆注册:
网盘管理主页
文件上传
新建文件夹
移动文件
视频文件在线播放
回收站管理:可以对文件进行恢复和删除
项目核心代码:
- package io.ddisk.controller;
-
- import io.ddisk.domain.dto.PageDTO;
- import io.ddisk.domain.enums.FileTypeEnum;
- import io.ddisk.domain.vo.DirTreeNode;
- import io.ddisk.domain.vo.FileVO;
- import io.ddisk.domain.vo.LoginUser;
- import io.ddisk.domain.vo.PathNodeVO;
- import io.ddisk.domain.vo.base.PageVO;
- import io.ddisk.service.UserFileService;
- import io.ddisk.utils.SpringWebUtils;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.Parameter;
- import io.swagger.v3.oas.annotations.Parameters;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import org.hibernate.validator.constraints.Length;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.http.ResponseEntity;
- import org.springframework.validation.annotation.Validated;
- import org.springframework.web.bind.annotation.*;
-
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotEmpty;
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Null;
- import java.util.List;
- import java.util.Map;
-
-
-
- @Tag(name = "File", description = "该接口为文件接口,主要用来做一些文件的基本操作,如创建目录,删除,移动,复制等。")
- @Validated
- @RestController
- @RequestMapping("/file")
- public class FileController {
-
- @Autowired
- private UserFileService userFileService;
-
-
- @Operation(summary = "获取目录及文件", description = "前端提供父目录和分页数据,返回该文件夹下的这些数据", tags = {"file"})
- @GetMapping(value = "/list")
- @Parameters({
- @Parameter(name = "pid", description = "用户文件目录id,需要登录用户的文件", required = true)
- })
- public ResponseEntity<PageVO<FileVO>> getFileList(@NotNull PageDTO page, @Length(min = 32, max = 32) @RequestParam(required = false) String pid) {
-
- LoginUser user = SpringWebUtils.requireLogin();
- PageVO<FileVO> fileListPage = userFileService.listTheDir(user.getId(), pid, page);
- return ResponseEntity.ok(fileListPage);
- }
-
- @Operation(summary = "获取某类型文件", description = "获取某一类型文件,例如图片、视频、文档等", tags = {"file"})
- @GetMapping(value = "/list/type")
- @Parameters({
- @Parameter(name = "fileType", description = "文件类型,图片文件,视频文件等", required = true)
- })
- public ResponseEntity<PageVO<FileVO>> getFileListByType(@NotNull PageDTO page, @NotNull FileTypeEnum fileType) {
-
- LoginUser user = SpringWebUtils.requireLogin();
- PageVO<FileVO> fileListPage = userFileService.listTheTypeFile(user.getId(), fileType, page);
- return ResponseEntity.ok(fileListPage);
- }
-
- @Operation(summary = "文件搜索", description = "模糊搜索文件名", tags = {"file"})
- @GetMapping(value = "/search")
- @Parameters({
- @Parameter(name = "filename", description = "模糊搜索文件名", required = true)
- })
- public ResponseEntity<PageVO<FileVO>> searchFile(@NotNull PageDTO page, @NotBlank String filename) {
-
- PageVO<FileVO> fileListPage = userFileService.searchFile(filename, page);
- return ResponseEntity.ok(fileListPage);
- }
-
- @Operation(summary = "获取目录树", description = "文件移动的时候需要用到该接口,用来展示目录树,展示机制为饱汉模式", tags = {"file"})
- @GetMapping(value = "/dir/tree")
- public ResponseEntity<DirTreeNode> getDirTree() {
-
- LoginUser user = SpringWebUtils.requireLogin();
- DirTreeNode tree = userFileService.dirTree(user.getId());
- return ResponseEntity.ok(tree);
- }
-
- @Operation(summary = "查询回收站文件", description = "查询某用户回收站所有文件", tags = {"file"})
- @GetMapping(value = "/list/recycle")
- public ResponseEntity<PageVO<FileVO>> listRecycleBin(@NotNull PageDTO page) {
-
- LoginUser user = SpringWebUtils.requireLogin();
- PageVO<FileVO> fileListPage = userFileService.listRecycle(user.getId(), page);
- return ResponseEntity.ok(fileListPage);
- }
-
- @Operation(summary = "父节点列表", description = "用于显示父路径,字典key为文件id", tags = {"file"})
- @GetMapping(value = "/path/tree")
- public ResponseEntity<Map<String, PathNodeVO>> getPathTree() {
-
- LoginUser user = SpringWebUtils.requireLogin();
- Map<String, PathNodeVO> pathTreeMap = userFileService.getPathTreeMap(user.getId());
- return ResponseEntity.ok(pathTreeMap);
- }
-
- @Operation(summary = "移动文件", description = "移动文件", tags = {"file"})
- @PostMapping(value = "/move")
- @Parameters({
- @Parameter(name = "from", description = "移动文件id", required = true),
- @Parameter(name = "to", description = "目标文件夹id", required = true)
- })
- public ResponseEntity<Void> move(@NotBlank @Length(min = 32, max = 32) String from, @Length(min = 32, max = 32) @RequestParam(required = false) String to) {
-
- userFileService.move(from, to);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "移动文件", description = "批量移动文件", tags = {"file"})
- @PostMapping(value = "/batch/move")
- @Parameters({
- @Parameter(name = "from", description = "移动文件id列表", required = true),
- @Parameter(name = "to", description = "目标文件夹id", required = true)
- })
- public ResponseEntity<Void> batchMove(@RequestParam(value = "from") @NotEmpty List<String> from, @Length(min = 32, max = 32)@RequestParam(required = false) String to) {
-
- userFileService.move(from, to);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "创建目录", description = "创建文件夹", tags = {"file"})
- @PostMapping(value = "/mkdir")
- @Parameters({
- @Parameter(name = "pid", description = "父目录id", required = false),
- @Parameter(name = "name", description = "目录名", required = true),
- })
- public ResponseEntity<Void> mkdir(@RequestParam(required = false) @Length(min = 32, max = 32) String pid, @NotBlank String name) {
- LoginUser user = SpringWebUtils.requireLogin();
- userFileService.mkdir(user.getId(), pid, name);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "重命名", description = "重命名文件名和扩展名", tags = {"file"})
- @PostMapping(value = "/rename")
- @Parameters({
- @Parameter(name = "userFileId", description = "文件id", required = true),
- @Parameter(name = "filename", description = "文件基础名", required = true),
- @Parameter(name = "extension", description = "文件扩展名", required = true),
- })
- public ResponseEntity<Void> rename(@NotBlank @Length(min = 32, max = 32) String userFileId, @NotBlank String filename, String extension) {
- userFileService.rename(userFileId, filename, extension);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "删除文件", description = "删除文件或文件夹", tags = {"file"})
- @PostMapping(value = "/delete")
- @Parameters({
- @Parameter(name = "userFileId", description = "文件id", required = true),
- })
- public ResponseEntity<Void> delete(@NotBlank @Length(min = 32, max = 32) String userFileId) {
- userFileService.delete(userFileId);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "批量删除文件", description = "批量删除文件或文件夹", tags = {"file"})
- @PostMapping(value = "/batch/delete")
- @Parameters({
- @Parameter(name = "userFileIds", description = "文件id列表", required = true),
- })
- public ResponseEntity<Void> batchDelete(@NotEmpty @RequestParam(value = "userFileIds") List<String> userFileIds) {
- userFileService.delete(userFileIds);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "恢复文件", description = "恢复回收站文件或文件夹", tags = {"file"})
- @PostMapping(value = "/recover")
- @Parameters({
- @Parameter(name = "userFileId", description = "文件id", required = true),
- })
- public ResponseEntity<Void> recover(@NotBlank @Length(min = 32, max = 32) String userFileId) {
- userFileService.recover(userFileId);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "批量恢复文件", description = "批量恢复回收站文件或文件夹", tags = {"file"})
- @PostMapping(value = "/batch/recover")
- @Parameters({
- @Parameter(name = "userFileIds", description = "文件id列表", required = true),
- })
- public ResponseEntity<Void> batchRecover(@NotEmpty @RequestParam(value = "userFileIds") List<String> userFileIds) {
- userFileService.recover(userFileIds);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "删除回收站文件", description = "真正的删除文件接口,删除回收站里的文件", tags = {"file"})
- @PostMapping(value = "/delete/recycle")
- @Parameters({
- @Parameter(name = "userFileId", description = "文件id", required = true),
- })
- public ResponseEntity<Void> deleteFromRecycleBin(@NotBlank @Length(min = 32, max = 32) String userFileId) {
- userFileService.deleteFromRecycleBin(userFileId);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "批量删除回收站文件", description = "真正的删除文件接口,删除回收站里的文件", tags = {"file"})
- @PostMapping(value = "/batch/delete/recycle")
- @Parameters({
- @Parameter(name = "userFileIds", description = "文件id列表", required = true),
- })
- public ResponseEntity<Void> batchDeleteFromRecycleBin(@RequestParam(value = "userFileIds") @NotEmpty List<String> userFileIds) {
- userFileService.deleteFromRecycleBin(userFileIds);
- return ResponseEntity.ok().build();
- }
-
- }
- package io.ddisk.controller;
-
- import io.ddisk.domain.dto.FileDTO;
- import io.ddisk.domain.dto.FileUploadDTO;
- import io.ddisk.domain.dto.MergeFileDTO;
- import io.ddisk.domain.entity.FileEntity;
- import io.ddisk.domain.vo.LoginUser;
- import io.ddisk.domain.vo.UploadFileVO;
- import io.ddisk.service.FileService;
- import io.ddisk.service.FileShareService;
- import io.ddisk.utils.ResponseUtils;
- import io.ddisk.utils.SpringWebUtils;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.Parameter;
- import io.swagger.v3.oas.annotations.Parameters;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import jodd.bean.BeanCopy;
- import lombok.extern.slf4j.Slf4j;
- import org.hibernate.validator.constraints.Length;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.http.ResponseEntity;
- import org.springframework.validation.annotation.Validated;
- import org.springframework.web.bind.annotation.*;
-
- import javax.validation.constraints.NotBlank;
- import java.util.Collection;
- import java.util.Objects;
-
-
- @Slf4j
- @Tag(name = "FileTransfer", description = "该接口为文件传输接口,主要用来做文件的上传和下载")
- @RequestMapping("transfer")
- @Validated
- @RestController
- public class FileTransferController {
-
- @Autowired
- private FileService fileService;
-
- @Autowired
- private FileShareService fileShareService;
-
- @Operation(summary = "极速上传", description = "校验文件MD5判断文件是否存在,如果存在直接上传成功并返回skipUpload=true,如果不存在返回skipUpload=false")
- @GetMapping("upload")
- @ResponseBody
- public ResponseEntity<UploadFileVO> uploadFileSpeed(@Validated FileUploadDTO fileUploadDto){
- LoginUser user = SpringWebUtils.requireLogin();
- FileEntity fileEntity = fileService.speedUpload(user.getId(), fileUploadDto);
- Collection<Integer> uploaded = fileService.getUploaded(fileUploadDto.getIdentifier(), fileUploadDto.getChunkSize());
- return ResponseEntity.ok(new UploadFileVO(false, Objects.nonNull(fileEntity), uploaded));
- }
-
-
- @Operation(summary = "上传文件", description = "真正的上传文件接口")
- @PostMapping("upload")
- public ResponseEntity<UploadFileVO> uploadChunk(@Validated FileUploadDTO fileUploadDto) {
- LoginUser user = SpringWebUtils.requireLogin();
- Collection<Integer> uploaded = fileService.upload(user.getId(), fileUploadDto);
- return ResponseEntity.ok(new UploadFileVO(uploaded.size()==fileUploadDto.getTotalChunks(), false, uploaded));
- }
-
- @Operation(summary = "下载文件", description = "文件下载接口,保证文件安全,阻止非法用户下载")
- @GetMapping("download/{userFileId}")
- @Parameters({
- @Parameter(name = "userFileId", description = "用户文件id,需要登录用户的文件", required = true)
- })
- public void downloadFile(@PathVariable @NotBlank @Length(min = 32, max = 32) String userFileId){
-
- LoginUser user = SpringWebUtils.requireLogin();
- FileDTO fileDTO = fileService.getFileResource(user.getId(), user.getRole(), userFileId);
- ResponseUtils.sendFile(fileDTO);
- }
-
- @Operation(summary = "下载文件", description = "文件下载接口,保证文件安全,阻止非法用户下载")
- @GetMapping("/anonymous/download/{shareId}")
- @Parameters({
- @Parameter(name = "userFileId", description = "用户文件id,需要登录用户的文件", required = true)
- })
- public void anonymousDownloadFile(@PathVariable @NotBlank @Length(min = 32, max = 32) String shareId){
-
- FileDTO fileDTO = fileShareService.getFileResource(shareId);
- ResponseUtils.sendFile(fileDTO);
- }
-
-
- @Operation(summary = "获取略缩图", description = "略缩图获取,用于图片类型文件的略缩图和头像")
- @GetMapping("thumbnail/{userFileId}")
- @Parameters({
- @Parameter(name = "userFileId", description = "用户文件id,需要登录用户的文件", required = true)
- })
- public void thumbnail(@PathVariable @NotBlank @Length(min = 32, max = 32) String userFileId){
-
- LoginUser user = SpringWebUtils.requireLogin();
- FileDTO fileDTO = fileService.getThumbnail(user.getId(), userFileId);
- ResponseUtils.sendFile(fileDTO);
- }
-
-
- @Operation(summary = "合并", description = "合并上传的切片文件")
- @PostMapping("merge")
- public ResponseEntity<Void> mergeFile(@Validated @RequestBody MergeFileDTO mergeFileDTO) {
-
- LoginUser user = SpringWebUtils.requireLogin();
- fileService.mergeFile(mergeFileDTO);
-
- FileUploadDTO uploadDTO = new FileUploadDTO();
- BeanCopy.from(mergeFileDTO).to(uploadDTO).copy();
-
- fileService.speedUpload(user.getId(), uploadDTO);
- log.info("用户[{}], 合并[{}]文件", user.getUsername(), uploadDTO.getIdentifier());
- return ResponseEntity.ok().build();
- }
-
- }
- package io.ddisk.controller;
-
- import io.ddisk.domain.dto.RegisterDTO;
- import io.ddisk.domain.vo.LoginUser;
- import io.ddisk.domain.vo.UserStorageVO;
- import io.ddisk.service.UserService;
- import io.ddisk.service.UserStorageService;
- import io.ddisk.utils.SpringWebUtils;
- import io.swagger.v3.oas.annotations.Operation;
- import io.swagger.v3.oas.annotations.Parameter;
- import io.swagger.v3.oas.annotations.Parameters;
- import io.swagger.v3.oas.annotations.tags.Tag;
- import org.hibernate.validator.constraints.Length;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.http.ResponseEntity;
- import org.springframework.validation.annotation.Validated;
- import org.springframework.web.bind.annotation.*;
-
- import javax.validation.constraints.Email;
- import javax.validation.constraints.NotBlank;
-
- /**
- * 用户的登录,注销交由spring security处理
- *
- */
- @Tag(name = "User", description = "该接口为用户接口,主要做用户登录,注册和校验token")
- @RequestMapping("user")
- @Validated
- @RestController
- public class UserController {
-
- @Autowired
- private UserService userService;
- @Autowired
- private UserStorageService userStorageService;
-
- @Operation(summary = "用户注册, 步骤一", description = "获取注册令牌,令牌发送至用户邮箱", tags = {"user"})
- @GetMapping(value = "register")
- @Parameters({
- @Parameter(name = "email", description = "用户邮箱", required = true)
- })
- public ResponseEntity<Void> sendRegisterToken(@Email String email) {
-
- userService.sendEmailToRegister(email);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "用户注册, 步骤二", description = "注册账号", tags = {"user"})
- @PostMapping(value = "register")
- public ResponseEntity<Void> registerUser(@Validated @RequestBody RegisterDTO registerDTO) {
-
- userService.addUser(registerDTO);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "设置头像", description = "设置用户头像", tags = {"user"})
- @PostMapping(value = "avatar")
- @Parameters({
- @Parameter(name = "fileId", description = "用户文件id", required = true)
- })
- public ResponseEntity<Void> setAvator(@NotBlank @Length(min = 32, max = 32) String fileId) {
-
- LoginUser user = SpringWebUtils.requireLogin();
- userService.setAvator(user.getId(), fileId);
- user.setImgUrl(fileId);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "获取用户信息", description = "获取用户信息", tags = {"user"})
- @GetMapping(value = "info")
- public ResponseEntity<LoginUser> getLoginUser() {
-
- return ResponseEntity.ok().body(SpringWebUtils.requireLogin());
- }
-
- @Operation(summary = "校验用户名", description = "检查用户是否已被注册", tags = {"user"})
- @GetMapping(value = "exist/username")
- @Parameters({
- @Parameter(name = "username", description = "用户名", required = true)
- })
- public ResponseEntity<Void> existUsername(
- @Length(min = 4, max = 16, message = "用户名长度必须在7-20位") String username) {
-
- userService.notExistUsername(username);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "校验邮箱", description = "检查邮箱是否已被使用", tags = {"user"})
- @GetMapping(value = "exist/email")
- @Parameters({
- @Parameter(name = "email", description = "用户邮箱", required = true)
- })
- public ResponseEntity<LoginUser> existEmail(@Email @NotBlank String email) {
-
- userService.notExistUsername(email);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "忘记密码,步骤1", description = "忘记密码之发送密码重置邮件", tags = {"user"})
- @GetMapping(value = "reset/passwd")
- @Parameters({
- @Parameter(name = "email", description = "用户邮箱", required = true)
- })
- public ResponseEntity<Void> forgetPasswd(@Email @NotBlank String email) {
-
- userService.sendEmailToResetPassword(email);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "忘记密码,步骤2", description = "忘记密码之重置密码", tags = {"user"})
- @PostMapping(value = "reset/passwd")
- @Parameters({
- @Parameter(name = "email", description = "用户邮箱", required = true),
- @Parameter(name = "password", description = "新密码", required = true),
- @Parameter(name = "token", description = "令牌,从邮件中获取", required = true)
- })
- public ResponseEntity<Void> regeneratePasswd(
- @Email @NotBlank String email,
- @Length(min = 7, max = 20, message = "密码长度必须在7-20位") String password,
- @Length(min = 36, max = 36, message = "密码长度必须在7-20位") String token) {
-
- userService.forgetPassword(email, password, token);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "修改密码", description = "修改密码", tags = {"user"})
- @Parameters({
- @Parameter(name = "oldPassword", description = "原密码", required = true),
- @Parameter(name = "newPassword", description = "新密码", required = true)
- })
- @GetMapping(value = "passwd")
- public ResponseEntity<Void> passwd(
- @Length(min = 7, max = 20, message = "密码长度必须在7-20位") String oldPassword,
- @Length(min = 7, max = 20, message = "密码长度必须在7-20位") String newPassword
- ) {
- LoginUser user = SpringWebUtils.requireLogin();
- userService.passwd(user.getId(), oldPassword, newPassword);
- return ResponseEntity.ok().build();
- }
-
- @Operation(summary = "用户内存使用", description = "获取用户磁盘信息,已使用和未使用大小", tags = {"user"})
- @GetMapping(value = "storage/info")
- public ResponseEntity<UserStorageVO> getStorageInfo() {
-
- UserStorageVO vo = userStorageService.getStorageInfo(SpringWebUtils.requireLogin());
- return ResponseEntity.ok().body(vo);
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。