go语言实现文件夹上传前后端代码案例
前端用于上传的测试界面
- 如果上传的文件夹有子文件要遍历子文件夹创建出子文件夹再进行拷贝
- 需要获取文件名和对应的路径,将文件的相对路径和文件对象添加到FormData中
- 这几行代码很关键
for (let i = 0; i < files.length; i++) {formData.append('model_folder', files[i], files[i].webkitRelativePath);}
前端代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Upload Folder Example</title>
</head>
<body>
<input type="file" id="folderInput" webkitdirectory mozdirectory directory multiple>
<button onclick="uploadFolder()">Upload</button><script>function uploadFolder() {let input = document.getElementById('folderInput');// 确保用户选择了一个文件夹if (!input.files || !input.files.length) {return alert('Please select a folder to upload.');}let files = input.files;let formData = new FormData();// 将文件的相对路径和文件对象添加到FormData中for (let i = 0; i < files.length; i++) {formData.append('model_folder', files[i], files[i].webkitRelativePath);}// 创建一个 XMLHttpRequest 对象进行异步请求let request = new XMLHttpRequest();request.open('POST', 'http://localhost:8089/digitalPerson/modeFile', true);request.onload = function() {if (request.status === 200) {// 文件上传成功的处理console.log(request.responseText);} else {// 文件上传失败的处理console.error(request.responseText);}};// 发送FormData对象到服务器request.send(formData);}
</script>
</body>
</html>
后端使用gin实现文件夹的上传和保存到对应的路径
package controllersimport ("PsycheEpic/src/utils""errors""fmt""github.com/gin-gonic/gin""net/http""os""path/filepath""strings"
)// 处理文件夹上传
func UploadFolderHandler(c *gin.Context, digitalId int64) error {err := c.Request.ParseMultipartForm(0) // 不限制上传文件大小if err != nil {c.JSON(http.StatusOK, gin.H{"code": 0,"message": err.Error(),})return errors.New("获取上传的文件失败")}//digitalId := 3// 数字人ID转换为字符串digital_Id := utils.Strval(digitalId)modePath := filepath.Join("./static/HuaSoul/asset/", digital_Id)fmt.Println("digitalId: ", digitalId)// 检查上传的文件是否存在form, err := c.MultipartForm()files := form.File["model_folder"] // 'files' 是前端 JavaScript 中指定的字段名if err != nil {c.JSON(http.StatusOK, gin.H{"code": 0,"message": "missing uploaded file"})return errors.New("丢失上传的文件")}// 创建模型文件夹if err := os.MkdirAll(modePath, 0755); err != nil {c.JSON(http.StatusOK, gin.H{"code": 0,"message": "failed to create model folder",})return errors.New("failed to create model folder")}// 遍历上传的文件for _, file := range files {fileName := file.Header["Content-Disposition"]path, _ := GetFileName(fileName)fmt.Println("path: ", path)savePath := filepath.Join(modePath, path) // 保存文件的路径,确保'uploads'文件夹已存在或自动创建if err := c.SaveUploadedFile(file, savePath); err != nil {c.String(http.StatusOK, fmt.Sprintf("'%s' could not be saved: %v", file.Filename, err))return err}}// 上传成功后返回响应//c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))return nil
}//fileName [form-data; name="model_folder"; filename="test/头像.jpg"] ;取出文件名
func GetFileName(fileName []string) (string, error) {for _, f := range fileName {// 判断字符串是否包含了需要查找的文件名关键字if strings.Contains(f, `filename=`) {// 按照 filename=" 分割parts := strings.Split(f, `filename="`)if len(parts) < 2 {// 没有找到分隔符,跳到下一个元素continue}// 按照 " 分割以获取实际的文件路径filePathParts := strings.SplitN(parts[1], `"`, 2)// 如果成功找到路径就返回if len(filePathParts) >= 2 {return filePathParts[0], nil // 返回找到的路径}}}// 如果没有找到,返回错误return "", fmt.Errorf("no path found")
}