Forráskód Böngészése

文件批量上传,file未添加

Administrator 1 éve
szülő
commit
b492f26f6e

+ 9 - 0
gin/GinService.go

@@ -5,6 +5,7 @@ import (
 	"file/db"
 	"file/entity"
 	"file/gin/router"
+	"file/util"
 	"fmt"
 	"github.com/gin-gonic/gin"
 )
@@ -33,7 +34,10 @@ func RunGin() {
 func baseRouter() {
 	pageRouter("")
 	authRouter("/auth")
+	//权限校验
+	engine.Use(util.ValidateToken())
 	userRouter("/user")
+	fileRouter("/file")
 }
 
 func pageRouter(rootPath string) {
@@ -52,3 +56,8 @@ func authRouter(rootPath string) {
 	group.POST("/login", router.Login)
 
 }
+func fileRouter(rootPath string) {
+	group := engine.RouterGroup.Group(rootPath)
+	group.POST("/upload", router.UploadFile)
+
+}

+ 87 - 0
gin/router/FileRouter.go

@@ -0,0 +1,87 @@
+package router
+
+import (
+	"file/entity"
+	"file/gin/service"
+	"file/util"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"net/http"
+	"strings"
+)
+
+func UploadFile(c *gin.Context) {
+	// 获取上传的所有文件
+	form, err := c.MultipartForm()
+	if err != nil {
+		c.JSON(http.StatusBadRequest, CreateResultError(400, "Failed to parse form"))
+		return
+	}
+
+	// 获取所有上传的文件
+	files := form.File["files[]"]
+	if len(files) == 0 {
+		c.JSON(http.StatusBadRequest, CreateResultError(400, "No files uploaded"))
+		return
+	}
+	//获取用户名称
+	cookie, err := c.Cookie("token")
+	if err != nil {
+		c.JSON(http.StatusUnauthorized, CreateResultError(401, "Failed to get token"))
+		return
+	}
+	claims, err := util.ValidateTokenToMyClaims(cookie)
+	if err != nil {
+		c.JSON(http.StatusUnauthorized, CreateResultError(401, err.Error()))
+		return
+	}
+	fmt.Println(claims.Id)
+	user, err := service.UserDao{}.GetById(claims.Id)
+	if err != nil {
+		c.JSON(http.StatusInternalServerError, CreateResultError(500, "Failed to get user"))
+		return
+	}
+
+	// 遍历文件并保存
+	for _, file := range files {
+		// 获取文件路径
+		pars := strings.Split(file.Header.Get("Content-Disposition"), ";")
+		path := ""
+		for i := range pars {
+			split := strings.Split(pars[i], "=")
+			if len(split) > 1 && strings.TrimSpace(split[0]) == "filename" {
+				path = strings.Trim(split[1], "\"")
+				break
+			}
+		}
+
+		fmt.Println(file.Filename, file.Size, path)
+		// 创建目录
+		dst := fmt.Sprintf("./uploads/%s/%s", user.Username, path)
+		fmt.Println("==> ", dst)
+		err := c.SaveUploadedFile(file, dst)
+		if err != nil {
+			c.JSON(http.StatusInternalServerError, CreateResultError(400, "Failed to save file"))
+			return
+		}
+	}
+
+	// 返回成功消息
+	c.JSON(http.StatusOK, CreateResult())
+}
+func computeFile(name, path, fileType string, size int64) entity.File {
+	return entity.File{
+		Name:       name,
+		Url:        path,
+		Size:       size,
+		Type:       fileType,
+		MD5:        "",
+		ParentId:   "",
+		Extension:  "",
+		Access:     "",
+		CreateUser: 0,
+		CreateTime: 0,
+		UpdateTime: 0,
+	}
+
+}

+ 33 - 0
gin/service/FileRouter.go

@@ -0,0 +1,33 @@
+package service
+
+import (
+	"file/db"
+	"file/entity"
+)
+
+type FileDao struct{}
+
+func Insert(file entity.File) error {
+	_, err := db.DBEngin.Table("file").Insert(&file)
+	return err
+}
+func BatchInsert(files []entity.File) error {
+	table := db.DBEngin.Table("file")
+	err := table.Begin()
+	defer func() {
+		if err != nil {
+			err := table.Rollback()
+			if err != nil {
+				return
+			}
+		} else {
+			err := table.Commit()
+			if err != nil {
+				table.Rollback()
+				return
+			}
+		}
+	}()
+	_, err = table.Insert(&files)
+	return err
+}

+ 10 - 1
gin/service/UserDao.go

@@ -1,14 +1,23 @@
 package service
 
 import (
+	"errors"
 	"file/db"
 	"file/entity"
 )
 
 type UserDao struct{}
 
-func (dao *UserDao) GetAll(user entity.User) ([]entity.User, int64, error) {
+func (dao UserDao) GetAll(user entity.User) ([]entity.User, int64, error) {
 	var users []entity.User
 	count, err := db.DBEngin.Table("user").FindAndCount(&users, &user)
 	return users, count, err
 }
+func (dao UserDao) GetById(id int64) (entity.User, error) {
+	var user entity.User
+	res, err := db.DBEngin.Table("user").Where("id=?", id).Get(&user)
+	if !res {
+		return user, errors.New("用户不存在")
+	}
+	return user, err
+}

+ 79 - 0
gin/static/css/index.css

@@ -68,3 +68,82 @@
     font-size: 14px;
     margin-top: 10px;
 }
+
+#content-page {
+    font-family: Arial, sans-serif;
+    background-color: #f4f4f4;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    height: 100vh;
+}
+
+#content-page .nav-bar {
+    background-color: #333;
+    width: 100VW;
+    /*height: 2.7vw;*/
+    min-height: 50px;
+    display: flex;
+    justify-content: space-between;
+    line-height: 50px;
+}
+
+#content-page .nav-bar .nav-logo {
+    display: flex;
+    width: 100px;
+    margin-right: 20px;
+    background-color: rgba(255, 255, 255, 0.07);
+
+}
+
+#content-page .nav-bar .nav-menu {
+    display: flex;
+}
+#content-page .nav-bar .nav-menu .nav-menu-item{
+    margin-left: 5px;
+    color: #dddddd;
+    font-size: 17px;
+    font-weight: bold;
+    border-bottom: 5px solid rgba(255,255,255,0.6);
+    padding: 0 10px;
+    cursor: pointer;
+    user-select: none;
+    min-width: 95px;
+    text-align: center;
+}
+#content-page .nav-bar .nav-menu .nav-menu-item:hover{
+    color: #f4f4f4;
+    background-color: rgba(255,255,255,0.07);
+}
+#content-page .nav-bar .nav-user {
+    margin-left: auto;
+    width: 80px;
+    background-color: rgba(255, 255, 255, 0.07);
+}
+
+#content-page .content-body {
+
+    height: calc(100VH - 2.70vw);
+}
+#content-page #drop-zone {
+    cursor: pointer;
+    width: 400px;
+    height: 200px;
+    border: 2px dashed #ccc;
+    text-align: center;
+    line-height: 200px;
+    color: #666;
+    font-size: 16px;
+    margin: 20px auto;
+    background-color: #f9f9f9;
+    transition: border 0.2s ease-in-out;
+    user-select: none;
+}
+#content-page #drop-zone:hover {
+    border: 2px dashed #3089ff;
+}
+#content-page #drop-zone.dragover {
+    background-color: #e0e0e0;
+
+    border: 2px dashed #3089ff;
+}

+ 73 - 10
gin/template/index/content.tmpl

@@ -1,15 +1,78 @@
-<div>
-    首页<br>
-    文件管理<br>
-    用户管理<br>
+<div id="content-page">
+    <div class="nav-bar">
+        <div class="nav-logo"></div>
+        <div class="nav-menu">
+            <div class="nav-menu-item">首页</div>
+            <div class="nav-menu-item">文件管理</div>
+            <div class="nav-menu-item">用户管理</div>
+        </div>
+        <div class="nav-user"></div>
+    </div>
+    <div class="content-body">
+        <div id="drop-zone">拖拽文件到这里,或者点击选择文件</div>
+        <input type="file" id="file-input" style="display: none;" webkitdirectory directory/>
+
+        存储文件信息<br/>
+        文件快捷上传<br/>
+        服务器信息查看(负载、内存、硬盘)<br/>
+        文件下载<br/>
+    </div>
 </div>
-<div class="first-page">
-    存储文件信息<br/>
-    文件快捷上传<br/>
-    服务器信息查看(负载、内存、硬盘)<br/>
-    文件下载<br/>
+<script>
+    const dropZone = document.getElementById('drop-zone');
+    const fileInput = document.getElementById('file-input');
+
+    // 点击区域,打开文件选择框
+    dropZone.addEventListener('click', () => {
+        fileInput.click();
+    });
+
+    // 文件选择框改变事件
+    fileInput.addEventListener('change', (event) => {
+        handleFiles(event.target.files);
+    });
+
+    // 拖拽事件处理
+    dropZone.addEventListener('dragover', (event) => {
+        event.preventDefault(); // 必须阻止默认行为才能触发 drop 事件
+        dropZone.classList.add('dragover');
+    });
+
+    dropZone.addEventListener('dragleave', () => {
+        dropZone.classList.remove('dragover');
+    });
 
+    dropZone.addEventListener('drop', (event) => {
+        event.preventDefault(); // 阻止默认行为
+        dropZone.classList.remove('dragover');
+        const files = event.dataTransfer.files;
+        handleFiles(files);
+    });
 
+    function handleFiles(files) {
+        if (files.length > 0) {
+            const formData = new FormData();
 
+            // 遍历文件夹中的每个文件
+            for (let i = 0; i < files.length; i++) {
+                formData.append("files[]", files[i]); // 'files[]' 是后端接收的字段名
+            }
 
-</div>
+            // 创建一个请求对象,上传文件到后端
+            fetch("/file/upload", {
+                method: "POST",
+                body: formData,
+                // headers: {
+                //     "Content-Type": "multipart/form-data",
+                // }
+            })
+                .then(response => response.json())
+                .then(data => {
+                    alert(data.message); // 返回的服务器响应
+                })
+                .catch(error => {
+                    alert("上传失败: " + error.message);
+                });
+        }
+    }
+</script>

+ 24 - 2
util/TokenUtil.go

@@ -1,6 +1,7 @@
 package util
 
 import (
+	"errors"
 	"fmt"
 	"github.com/dgrijalva/jwt-go"
 	"net/http"
@@ -43,9 +44,15 @@ func GenerateToken(id int64, role string) (string, int64, error) {
 func ValidateToken() gin.HandlerFunc {
 	return func(c *gin.Context) {
 		// 获取请求中的token
-		tokenString := c.GetHeader("Authorization")
+		tokenString, err := c.Cookie("token")
+		if err != nil {
+			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Authorization token is missing"})
+			c.Abort()
+			return
+		}
+		fmt.Println(tokenString)
 		if tokenString == "" {
-			c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization token is missing"})
+			c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "Authorization token is missing"})
 			c.Abort()
 			return
 		}
@@ -69,6 +76,21 @@ func ValidateToken() gin.HandlerFunc {
 		c.Next() // Token验证通过,继续执行后续处理
 	}
 }
+func ValidateTokenToMyClaims(tokenString string) (*MyClaims, error) {
+	token, _ := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
+		return secretKey, nil
+	})
+	if token == nil || !token.Valid {
+
+		return nil, errors.New("Invalid token")
+	}
+	mc, ok := token.Claims.(*MyClaims)
+	if !ok {
+		return nil, errors.New("Invalid token")
+	}
+	return mc, nil
+}
+
 func ParseJWTWithValidation(tokenString string) (*MyClaims, error) {
 	// 解析Token
 	token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {