数据校验部分参考https://juejin.cn/post/6863765115456454664#heading-7,没有使用 github.com/go-playground/validator/v10,进行更复杂的校验时可以使用

ShouldBind 可以i绑定各种请求的参数到对应的结构体上

  • 结构体的field必须大写字母开头,否则该field无法绑定
  • form:“age” 表示请求的参数的key是age,比如此时/b1/age=1可以绑定到user.Age,/b1/Age=1不可以绑定
  • json:“age” 表示把u以json返回时,Age的key是age
  • binding:“required” 表示此字段绑定失败会提示错误。不终止程序,其他字段能继续绑定
  • min/max:字符串的最小/大位数
  • lte/gte/lt/gt: 小于等于/大于等于/小于/大于
  • email:需要email格式
  • eqfield=AnotherFiled:本字段的值需要等于AnotherFiled字段的值
  • oneof=m f:需要是m或者f中的一个

文件上传

  • MultipartForm处理多个或者单个文件,FormFile单个文件,推荐MultipartForm
  • MultipartForm的返回值是*multipart.Form,此结构体有两个field,分别是Value map[string][]string和File map[string][]*FileHeader
  • 代码里,key是html文件里file的name属性,file_是[]*FileHeader(FileHeader切片),所以取得文件要用file_[0]
  • fmt.Sprintf用来拼接字符串,类似python的"xxx{}xx".format
  • path.Ext获取文件后缀名

前端传多个文件,且不同文件对应不同的name,可以用这个代码。
如果多个文件用同一个name以数组的形式传递,只能获取第一个文件。此时代码参考https://blog.csdn.net/weixin_43292547/article/details/126933263

package main

import (
	"fmt"
	"html/template"
	"log"
	"mime/multipart"
	"net/http"
	"path"
	"time"
	"github.com/gin-gonic/gin"
)

func main() {
	mainGin()
}

func mainGin() {
	r := gin.Default()
	
	//据说可以限制文件大小,不起作用
	// r.MaxMultipartMemory=1 << 20   //1*(2^10)*(2^10)=1m
	r.MaxMultipartMemory= 1
	
	r.Any("/b2", func(c *gin.Context) {
		c.HTML(http.StatusOK, "upload.html", nil)
	})
	
	r.Any("/b1", func(c *gin.Context) {
		type user struct {
			Name   string `binding:"required,min=2,max=4"`
			Age    int8   `form:"age" json:"age" binding:"required,gte=1,lte=9"`
			Weight float32
			Email  string `binding:"required,email"`
			Email2 string `binding:"required,eqfield=Email"`
			Gender string `binding:"required,oneof=m f"`
		}
		var (
			u   user
			f   *multipart.Form
			err error
		)
		if err = c.ShouldBind(&u); err != nil {
			goto End
		} else {
			log.Println(u)
		}

		// 上传多个文件或单个文件
		f, err = c.MultipartForm()
		//fmt.Printf("\nf:%v", f)
		if err != nil {
			goto End
		} else {
			files:=f.File
			//fmt.Printf("\nfiles:%v", files)
			//这里key是html文件里file的name属性,file_是[]*FileHeader(FileHeader切片)
			for key, file_ := range files{
				f:=file_[0]
				//fmt.Printf("\n key:%s:%s", key,f.Filename)
				//path.Ext获取文件后缀名
				dest := fmt.Sprintf("./upload/%d-%s%s",  time.Now().Unix(),key,path.Ext(f.Filename))
				//fmt.Println(dest)
				if err = c.SaveUploadedFile(f, dest); err != nil {
					goto End
				}
			}
		}

		// 上传单个文件
		// f, err = c.FormFile("file1")
		// if err != nil {
		// 	goto End
		// } else {
		// 	dest := path.Join("./upload", f.Filename)
		// 	fmt.Println(dest)
		// 	if err = c.SaveUploadedFile(f, dest); err != nil {
		// 		goto End
		// 	}
		// }
	End:
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"err": err.Error()})
		} else {
			c.JSON(http.StatusOK, u)
		}

	})
//template\upload.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form method='post' action='b1' enctype='multipart/form-data'>
        <input name="Name" value="aa"/><br/>
        <input name="age" value="3"/><br/>
        <input name="Weight" value="2.3"/><br/>
        <input name="Email" value="1@a.c"/><br/>
        <input name="Email2" value="1@a.c"/><br/>
        <input name="Gender" value="m"/><br/>
        <input name="file1" type="file"/><br/>
        <input name="file2" type="file"/><br/>
        <button type="submit">submit</button><br/>
    </form>
</body>
</html>
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐