diff --git a/driver/src/main/java/xyz/longicorn/driver/controller/UploadController.java b/driver/src/main/java/xyz/longicorn/driver/controller/UploadController.java index f5b085e..cf58682 100644 --- a/driver/src/main/java/xyz/longicorn/driver/controller/UploadController.java +++ b/driver/src/main/java/xyz/longicorn/driver/controller/UploadController.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import xyz.longicorn.driver.config.BizException; import xyz.longicorn.driver.dto.ApiResult; +import xyz.longicorn.driver.dto.FastUploadFile; import xyz.longicorn.driver.pojo.FileInfo; import xyz.longicorn.driver.pojo.FolderInfo; import xyz.longicorn.driver.service.FileService; @@ -54,17 +55,11 @@ public class UploadController { } fileInfo.setFolderId(folder.getId()); } - fileInfo.setUid(1l); + fileInfo.setUid(1); fileInfo.setHash(md5);// fileInfo.setName(file.getOriginalFilename()); fileInfo.setSize(file.getSize()); - String type = file.getContentType().toLowerCase(); - if (FILE_MIME_TYPE.containsKey(type)) { - type = FILE_MIME_TYPE.get(type); - } else { - type = "file"; - } - fileInfo.setType(type); + fileInfo.setType(getType(file.getContentType())); if (f != null) { // 系统已经存在了该文件 // 不保存上传文件 直接copy数据 fileInfo.setPath(f.getPath()); @@ -77,4 +72,23 @@ public class UploadController { fileService.save(fileInfo);//保存文件信息 return ApiResult.success(null); } + + // 将mimetype -> 文件后缀名的类型 + private String getType(String mimeType) { + String type = mimeType.toLowerCase(); + if (FILE_MIME_TYPE.containsKey(type)) { + return FILE_MIME_TYPE.get(type); + } + return "file"; + } + + @PostMapping("/fast-upload") + public ApiResult fastUpload(@RequestBody FastUploadFile file) { + int uid = 1; + + file.setType(getType(file.getType())); + + FileInfo info = fileService.fastUpload(uid, file); + return ApiResult.success(info); + } } diff --git a/driver/src/main/java/xyz/longicorn/driver/dao/FolderInfoMapper.java b/driver/src/main/java/xyz/longicorn/driver/dao/FolderInfoMapper.java index 293fcf5..46ca11e 100644 --- a/driver/src/main/java/xyz/longicorn/driver/dao/FolderInfoMapper.java +++ b/driver/src/main/java/xyz/longicorn/driver/dao/FolderInfoMapper.java @@ -2,8 +2,10 @@ package xyz.longicorn.driver.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import xyz.longicorn.driver.pojo.FolderInfo; @Mapper public interface FolderInfoMapper extends BaseMapper { + public FolderInfo getByPath(@Param("uid") int uid, @Param("path") String path); } diff --git a/driver/src/main/java/xyz/longicorn/driver/dto/FastUploadFile.java b/driver/src/main/java/xyz/longicorn/driver/dto/FastUploadFile.java new file mode 100644 index 0000000..a45eb23 --- /dev/null +++ b/driver/src/main/java/xyz/longicorn/driver/dto/FastUploadFile.java @@ -0,0 +1,12 @@ +package xyz.longicorn.driver.dto; + +import lombok.Data; + +@Data +public class FastUploadFile { + private String name; + private Long size; + private String type; + private String hash; + private String folder; +} diff --git a/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java b/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java index 42524c8..25f7a7f 100644 --- a/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java +++ b/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java @@ -19,7 +19,7 @@ import java.util.Date; @Accessors(chain = true) public class FileInfo implements Serializable { private Long id; - private Long uid; + private Integer uid; private String name; private String hash; private Long folderId; diff --git a/driver/src/main/java/xyz/longicorn/driver/service/FileService.java b/driver/src/main/java/xyz/longicorn/driver/service/FileService.java index 66d57b6..4600bcf 100644 --- a/driver/src/main/java/xyz/longicorn/driver/service/FileService.java +++ b/driver/src/main/java/xyz/longicorn/driver/service/FileService.java @@ -3,13 +3,21 @@ package xyz.longicorn.driver.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; +import xyz.longicorn.driver.config.BizException; import xyz.longicorn.driver.dao.FileInfoMapper; +import xyz.longicorn.driver.dao.FolderInfoMapper; +import xyz.longicorn.driver.dto.FastUploadFile; import xyz.longicorn.driver.pojo.FileInfo; +import xyz.longicorn.driver.pojo.FolderInfo; +import javax.annotation.Resource; import java.util.List; @Service public class FileService extends ServiceImpl { + @Resource + private FolderInfoMapper folderInfoMapper; + /** * 查询了目录下的文件列表集合 * @@ -31,4 +39,26 @@ public class FileService extends ServiceImpl { q.last("limit 1"); return this.getOne(q); } + + public FileInfo fastUpload(int uid, FastUploadFile file) { + long folderId = 0; + if (!"/".equals(file.getFolder())) { // 不是根目录 + final FolderInfo folder = folderInfoMapper.getByPath(uid, file.getFolder()); + if (null == folder) throw BizException.create("保存目录不存在"); + folderId = folder.getId(); // 设置上传目录编号 + } + + FileInfo info = this.getByMd5(file.getHash());//查询是否存在要上传的文件 + if (info == null) return null; // 没有存在 只能走普通上传 + // + FileInfo newFile = new FileInfo(); // 要保存的数据 + newFile.setPath(info.getPath()); + newFile.setHash(info.getHash()); + newFile.setType(file.getType()); + newFile.setFolderId(folderId); + newFile.setUid(uid); + newFile.setName(file.getName()); + newFile.setSize(info.getSize()); + return this.save(newFile) ? newFile : null; + } } diff --git a/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java b/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java index b6fb734..8402807 100644 --- a/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java +++ b/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java @@ -26,10 +26,7 @@ public class FolderService extends ServiceImpl { * @return */ public FolderInfo getByPath(int uid, String path) { - QueryWrapper q = new QueryWrapper(); - q.eq("uid", uid); - q.eq("path", path); - return this.getOne(q); + return this.getBaseMapper().getByPath(uid, path); } /** @@ -85,7 +82,7 @@ public class FolderService extends ServiceImpl { fNew.setUid(uid); fNew.setName(name); fNew.setParentId(parentId); - fNew.setPath((parent.equals("/")?"":parent) + "/" + name); + fNew.setPath((parent.equals("/") ? "" : parent) + "/" + name); return this.save(fNew) ? fNew : null; } } diff --git a/driver/src/main/resources/mapper/FolderInfoMapper.xml b/driver/src/main/resources/mapper/FolderInfoMapper.xml new file mode 100644 index 0000000..c1f49cf --- /dev/null +++ b/driver/src/main/resources/mapper/FolderInfoMapper.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/web/package-lock.json b/web/package-lock.json index b6ba5a5..84ca50e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@vitejs/plugin-vue": "^2.3.1", + "@vue/reactivity": "^3.2.33", "vite": "^2.9.7" } }, diff --git a/web/package.json b/web/package.json index 4dec2e8..aee4bfd 100644 --- a/web/package.json +++ b/web/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@vitejs/plugin-vue": "^2.3.1", + "@vue/reactivity": "^3.2.33", "vite": "^2.9.7" } } diff --git a/web/src/Main.vue b/web/src/Main.vue index 704a04b..c6ff319 100644 --- a/web/src/Main.vue +++ b/web/src/Main.vue @@ -5,6 +5,7 @@ import {dayjs, ElMessage, ElMessageBox} from 'element-plus' import api from "./service/api"; import qs from "qs"; import FileUploader from "./components/file-uploader/Index.vue"; +import FileBlockItem from "./components/FileBlockItem.vue"; export default { setup(){ @@ -80,7 +81,7 @@ export default { return pathList; } }, - components: {FileUploader, FileIcon, ArrowDown, Grid, FolderAdd}, + components: {FileBlockItem, FileUploader, FileIcon, ArrowDown, Grid, FolderAdd}, mounted() { // window.addEventListener('popstate',()=>console.log(location.href)) window.addEventListener('hashchange', this.handleHashChange) // 添加监听 @@ -128,18 +129,6 @@ export default { ext = name.substr(extIndex); return name.substr(0, (15 - ext.length)) + "**" + ext; }, - showFile(file, e) { - console.log(e) - if (file.type != 'folder') { - console.log(this.$refs.fileIcon) - this.$refs.fileIcon?.showPreview(file); - return; - } - // this.loadFileByPath(file.path) - // console.log(file) - // window.history.pushState({},null,'/show?path=' + file.name) - location.hash = '?path=' + file.path - }, fileMenuClick(e) { window.alert(JSON.stringify(e)); }, @@ -335,18 +324,7 @@ export default { -
-
- -
-
{{ formatName(file.name) }}
-
- {{ - file.type == 'folder' ? formatDate(file.createTime) : formatSize(file.size) - }} -
-
+
diff --git a/web/src/components/FileBlockItem.vue b/web/src/components/FileBlockItem.vue new file mode 100644 index 0000000..b6711bf --- /dev/null +++ b/web/src/components/FileBlockItem.vue @@ -0,0 +1,74 @@ + + + + + \ No newline at end of file diff --git a/web/src/components/file-uploader/Index.vue b/web/src/components/file-uploader/Index.vue index d1e5a7e..bacc3cf 100644 --- a/web/src/components/file-uploader/Index.vue +++ b/web/src/components/file-uploader/Index.vue @@ -75,8 +75,9 @@ import FileUpload from "./FileUpload.vue"; import {Upload, CircleCloseFilled, CloseBold, ArrowDownBold} from '@element-plus/icons-vue' import Hash from 'browser-md5-file'; import api from "../../service/api"; - +// 创建计算hash的对象 const hash = new Hash(); + const FileStatus = { Processing: 0, Ready: 1, @@ -87,11 +88,11 @@ const FileStatus = { export default { name: "Index", - emits:{ + emits: { /** * 文件上传后的触发此事件 */ - uploadSuccess:null + uploadSuccess: null }, props: { /** @@ -129,19 +130,63 @@ export default { const index = this.fileListData.indexOf(file);// 获取到要删除的下表 this.fileListData.splice(index, 1) }, + /** + * + * @param {FileList} files + */ add(files) { this.showUploadList = true; Array.from(files).forEach(file => { - this.fileListData.push({ - id: this.fileId++, - file, - name: file.name, - status: FileStatus.Ready, - folder:this.currentFolder, // 随当前文件选择的目录 - progress: 0, - }) + const size = file.size / 1024 // KB + if (size < 1024) { // 小于 1024KB + hash.md5(file, (err, md5) => { + this.fastUpload(file, md5); + }, p => console.log(p)) + } else { + this.pushUploadFile(file, this.currentFolder) + } }) - this.startUpload();//直接上传 + }, + // 添加文件到列表 用于展示 + pushUploadFile(file, folder, status = FileStatus.Ready, progress = 0) { + const f = { + id: this.fileId++, + file, + name: file.name, + status, + folder, // 随当前文件选择的目录 + progress, + }; + this.fileListData.push(f); + this.uploadFile(f);//直接上传 + }, + /** + * + * @param {File} file + * @param hash + */ + fastUpload(file, hash) { + const folder = this.currentFolder; + api.file.fastUpload({ + name: file.name, + size: file.size, + type: file.type, + hash, + folder + }).then(ret => { + if (ret) { + this.$emit('upload-success', { + result: ret, + file: file + }) + // 已经上传成功了 + this.pushUploadFile(file, folder, FileStatus.Success, 100) + } else { + this.pushUploadFile(file, folder); + } + }).catch(e => { + this.pushUploadFile(file, folder); + }); }, startUpload() { this.fileListData.forEach(f => { @@ -152,17 +197,19 @@ export default { }) }, uploadFile(f) { - f.status = FileStatus.Uploading; - api.upload(f.folder, f.file, (p) => { - f.progress = p.progress - }).then(ret => { - console.log(ret) - f.status = FileStatus.Success; // - this.$emit('upload-success', { - result: ret.data, - file: f - }) - }).catch(e => console.log(e)); + if (f.status == FileStatus.Ready) { + f.status = FileStatus.Uploading; + api.file.upload(f.folder, f.file, (p) => { + f.progress = p.progress + }).then(ret => { + console.log(ret) + f.status = FileStatus.Success; // + this.$emit('upload-success', { + result: ret.data, + file: f + }) + }).catch(e => console.log(e)); + } } } diff --git a/web/src/service/api.js b/web/src/service/api.js index de4a6ba..e10067d 100644 --- a/web/src/service/api.js +++ b/web/src/service/api.js @@ -74,40 +74,50 @@ export default { return request(`/api/folder/create`, 'POST', {parent, name}); } }, - upload(parent, file, onProcess = null) { - // 上传文件到某个目录 - const postData = new FormData(); // 将数据封装成form表单 - postData.append("parent", parent); // 父目录 - postData.append("file", file);// 文件 - return new Promise((resolve, reject) => { - let request = new XMLHttpRequest(); - request.open('POST', API_PATH + '/api/upload'); - request.upload.addEventListener('progress', function (e) { - // upload progress as percentage - let progress = (e.loaded / e.total) * 100; - onProcess({ - uploaded: e.loaded, - total: e.total, - progress - }) - }); - request.addEventListener('load', function (e) { - // HTTP status message (200, 404 etc) - let ret = {message: null} - try { - ret = JSON.parse(request.response) - if (request.status == 200) { - resolve(JSON.parse(request.response)); - } else { - reject(Error(ret.message || '上传文件出错!')); + file: { + /** + * 快速上传 + * @param params + * @returns {Promise} + */ + fastUpload(params) { + return request('/api/fast-upload', 'POST', params); + }, + upload(parent, file, onProcess = null) { + // 上传文件到某个目录 + const postData = new FormData(); // 将数据封装成form表单 + postData.append("parent", parent); // 父目录 + postData.append("file", file);// 文件 + return new Promise((resolve, reject) => { + let request = new XMLHttpRequest(); + request.open('POST', API_PATH + '/api/upload'); + request.upload.addEventListener('progress', function (e) { + // upload progress as percentage + let progress = (e.loaded / e.total) * 100; + onProcess({ + uploaded: e.loaded, + total: e.total, + progress + }) + }); + request.addEventListener('load', function (e) { + // HTTP status message (200, 404 etc) + let ret = {message: null} + try { + ret = JSON.parse(request.response) + if (request.status == 200) { + resolve(JSON.parse(request.response)); + } else { + reject(Error(ret.message || '上传文件出错!')); + } + } catch (e) { + console.log(e) + reject(Error('上传文件异常')) } - } catch (e) { - console.log(e) - reject(Error('上传文件异常')) - } - }); - request.send(postData); - }) - // return request('/api/upload', 'FILE', postData, onProcess) + }); + request.send(postData); + }) + // return request('/api/upload', 'FILE', postData, onProcess) + } } } \ No newline at end of file diff --git a/web/src/service/type.d.ts b/web/src/service/type.d.ts index 3742e4b..8dc197a 100644 --- a/web/src/service/type.d.ts +++ b/web/src/service/type.d.ts @@ -11,4 +11,12 @@ declare type FileItem = { size: number, type: 'folder' | string, updateTime: string -} \ No newline at end of file +} +declare type FileIconInstance = { + file: FileItem, + ext: String, + /** + * 显示预览 + */ + showPreview: Function +}