当前位置: 首页 > 工具软件 > Form Slice > 使用案例 >

Form表单映射到 Go 结构体

湛光华
2023-12-01

Form表单映射到 Go 结构体

一、gorilla/schema

​ gorilla/schema可将前端传来的form表单自动映射到go语言的结构体上。可简化Golang后端对form表单各个属性值的获取,支持的参数类型如下:

bool
float variants (float32, float64)
int variants (int, int8, int16, int32, int64)
string
uint variants (uint, uint8, uint16, uint32, uint64)
struct
a pointer to one of the above types
a slice or a pointer to a slice of one of the above types

​ 其中不支持的类型如文件、图片等可做特殊处理,代码可见示例代码(带文件)

​ gihub地址 : https://github.com/gorilla/schema

本地下载安装命令:
go get -t github.com/gorilla/schema

二、使用步骤

1、解析request传来的Form表单

​ 使用 *http.Request 自带的方法进行解析form。

request.ParseMultipartForm(maxMemory)

重要(坑):

​ 当表单格式为application/x-www-form-urlencoded时, 使用 request.ParseForm()

​ 当表单格式为multipart/form-data时, 使用 request.ParseMultipartForm(maxMemory)

​ maxMemory 参数解释:此参数限制了request请求体存储在内存中的大小,其余部分将存储在硬盘的临时文件中,可根据需要设置为1024的整数倍。

2、映射到结构体

重要(坑)

​ 1)、当结构体不设置tag时,会按照结构体的属性名称和form表单的属性name值映射匹配。如下所示:

type Person struct {
	// 此时前端form表单的属性name值也必须为 ID, Phone
	ID  string
	Phone string
}

​ 2)、在结构体属性名称和form表单属性name值不相符时,需要通过设置结构体的tag来映射。gorilla/schema默认检索的tag为:schema,如下代码所示:

type Person struct {
	// 此处 tb_name、tb_phone等为前端form表单的各个属性名
	Name  string `schema:"tb_name"`
	Phone string `schema:"tb_phone"`
}

​ 3)、可通过decoder.SetAliasTag(tag)方法自定义需要检索的tag,将tag设置为自己的结构体标签。否则会映射失败,代码如下:

type Person struct {
	// 此处 tb_name、tb_phone等为前端form表单的各个属性名
	Name  string `json:"tb_name"`
	Phone string `json:"tb_phone"`
}
var decoder = schema.NewDecoder()
var student Student
decoder.SetAliasTag("json")
decoder.Decode(&student, request.PostForm)
3、对解析到的结构体进行处理

三、示例代码(带文件处理)

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/schema"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"strconv"
	"time"
)

var decoder = schema.NewDecoder()

// 此常量为存储上传文件的文件夹路径
const sourcePath = "D:\\files\\"

type Person struct {
	// 此处 tb_name、tb_phone等为前端form表单的各个属性名
	Name  string `json:"tb_name"`
	Phone string `json:"tb_phone"`
}

type Student struct {
	Person
	Id    int    `json:"tb_id"`
	Class string `json:"tb_class"`
	File  string `json:"tb_file"`
}

func HandlerPlus(writer http.ResponseWriter, request *http.Request) {
	// 1、解析前端form表单
	//   当表单格式为application/x-www-form-urlencoded时, 使用 request.ParseForm()
	//	 当表单格式为multipart/form-data时, 使用 request.ParseMultipartForm(maxMemory)
	err := request.ParseMultipartForm(1024)
	if err != nil {
		fmt.Println(err)
	}
	var student Student
	// 2、映射到结构体
	//	 此方法用于设置需要解析到的结构体的属性标签(非常重要,未设置或设置错误,将无法映射)
	decoder.SetAliasTag("json")
	err = decoder.Decode(&student, request.PostForm)
	if err != nil {
		fmt.Println(err)
	}
	// 文件处理部分
	// 此处 tb_file 为前端表单文件项属性的name值
	file, header, err := request.FormFile("tb_file")
	if err != nil {
		fmt.Println(err)
	}
	filePath, err := fileService(file, header)
	if err != nil {
		fmt.Println(err)
	} else {
		student.File = filePath
	}
	// 3、对解析到的对象进行处理, 如存储到数据库等
	fmt.Println(student)
	var res = map[string]string{
		"result": "success",
		"name":   student.Name,
		"phone":  student.Phone,
		"class":  student.Class,
		"file":   student.File,
	}
	response, _ := json.Marshal(res)
	writer.Header().Set("Content-Type", "application/json")
	writer.WriteHeader(http.StatusOK)
	writer.Write(response)
}

// 文件处理方法
func fileService(file multipart.File, header *multipart.FileHeader) (string, error) {
	timeStr := strconv.Itoa(int(time.Now().Unix())) // 时间戳
	filePath := sourcePath + "New" + "_" + timeStr + "_" + header.Filename
	_, err := os.Stat(sourcePath)
	if err != nil {
		os.Mkdir(sourcePath, os.ModePerm)
	}
	out, err := os.Create(filePath)
	if err != nil {
		return "", err
	}
	fmt.Println("the upload file name is : ", header.Filename)
	defer out.Close()
	_, err = io.Copy(out, file)
	if err != nil {
		return "", err
	}
	return filePath, err
}
 类似资料: