forms - 如何为具有 gin(框架)和 golang 接口(interface)的表单制作通用表单函数?

标签 forms go interface go-gin

我想创建一个函数来处理任何类型的表单。 我希望它能够处理任何类型的数据。 我正在尝试使用界面来完成这项任务。

type Person struct {
    name        string 
    lastName    string
}


func HTMLForm(c *gin.Context) {
    var f Person
    c.ShouldBind(&f)
    c.JSON(http.StatusOK, f)
}

// with this function i get the correct info

// output: {"name":"john","lastName":"snow"}

func HTMLForm(c *gin.Context) {
    var f interface{}
    c.ShouldBind(&f)
    c.JSON(http.StatusOK, f)
}

// when i use the interface to make it usefull for any type of that
// i get null

// output: null

func HTMLForm(c *gin.Context) {
    var f interface{}
    ShouldBindJSON(f)
    c.JSON(http.StatusOK, f)
}

// output: null

我想通过接口(interface)获得与“Person”数据类型相同的输出。

// Another example of how i am using f

type Login struct {
    User     string 
    Password string 
}

func main() {
    router := gin.Default()

    router.POST("/loginForm", func(c *gin.Context) {
        var f interface{}

        if err := c.ShouldBind(&f); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        c.JSON(http.StatusOK, f)
    })

    // Listen and serve on 0.0.0.0:8080
    router.Run(":8080")
}

// output: null

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 更新

我想尝试更好地解释我的问题。 也许这次更新它更清楚。

// Golang code
package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

// Binding from JSON
type Login struct {
    User     string `form:"user" json:"user" xml:"user"  binding:"required"`
    Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

func main() {
    router := gin.Default()

    router.LoadHTMLGlob("templates/*")

    router.GET("/login", GetLogin)
    router.POST("/loginJSON", PostJSONForm)
    router.POST("/loginXML", PostXMLForm)
    router.POST("/loginForm", PostHTMLForm)

    /*
        sudo lsof -n -i :8080
        kill -9 <PID>
    */
    router.Run(":8080")
}

func GetLogin(c *gin.Context) {
    c.HTML(http.StatusOK, "login.tmpl", nil)
}

// Example for binding JSON ({"user": "manu", "password": "123"})
// curl -v -X POST http://localhost:8080/loginJSON -H 'content-type: application/json' '{ "user": "manu", "password"="123" }'
func PostJSONForm(c *gin.Context) {
    //var json Login
    var json interface{}
    //var form map[string]interface{}

    if err := c.ShouldBindJSON(&json); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    /*
        if json.User != "manu" || json.Password != "123" {
            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    */

    c.JSON(http.StatusOK, "json")
    c.JSON(http.StatusOK, json)
}

// Example for binding XML (
//  <?xml version="1.0" encoding="UTF-8"?>
//  <root>
//      <user>user</user>
//      <password>123</password>
//  </root>)
// curl -v -X POST http://localhost:8080/loginXML -H 'content-type: application/json' -d '{ "user": "manu", "password"="123" }'
func PostXMLForm(c *gin.Context) {
    //var xml Login
    var xml interface{}
    //var form map[string]interface{}

    if err := c.ShouldBindXML(&xml); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    /*
        if xml.User != "manu" || xml.Password != "123" {
            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    */

    c.JSON(http.StatusOK, "xml")
    c.JSON(http.StatusOK, xml)
}

// Example for binding a HTML form (user=manu&password=123)
// curl -v -X POST http://localhost:8080/loginForm -H 'content-type: application/json' -d '{ "user": "manu", "password":"123" }'
func PostHTMLForm(c *gin.Context) {
    //var form Login
    var form interface{}
    //var form map[string]interface{}

    // This will infer what binder to use depending on the content-type header.
    if err := c.ShouldBind(&form); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    /*
        if form.User != "manu" || form.Password != "123" {
            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            return
        }
        c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    */

    c.JSON(http.StatusOK, "html")
    c.JSON(http.StatusOK, form)
}

//Template
<h1>Login</h1>
<form action="/loginForm" method="POST">
    <label>user:</label><br>
    <input type="text" name="user"><br>

    <label>password:</label><br>
    <input type="text" name="password"><br>

    <input type="submit">
</form>
  1. 我已经尝试了所有这些不同的变体。只有一个有效,我在下面解释更多。

  2. 如果我使用“var form Login”而不是“var from interface{}”,效果会很好。但我需要它能够处理任何数据类型,所以我需要它处理接口(interface){}。

  3. 我有一个“成功”的输出,只是有一个 interface{} 尝试:

$ curl -X POST http://localhost:8080/loginForm -H 'content-type: application/json' -d '{ "user": "manu", "password":"123"}'

输出:“html”{“密码”:“123”,“用户”:“manu”

  1. 但是当我在浏览器的 HTML 表单上使用它时,使用我发布的模板我得到:

输出:"html"null

  1. 我不确定我得到的(第 3 点)是否真的是一个成功的输出。当我使用 Login var 时,它工作正常,使用 curl 和 brower,它的输出是倒置的:

$ curl -X POST http://localhost:8080/loginForm -H 'content-type: application/json' -d '{ "user": "manu", "password":"123"}'

输出:“html”{“用户”:“manu”,“密码”:“123”

这是我目前能得到的所有信息。

最佳答案

这个版本的最后一个答案适用于 html 表单和 curl json 提交。

package main

import (
    "net/http"
    "fmt"

    "github.com/gin-gonic/gin"
)

// Binding from JSON
type Login struct {
    User     string `form:"user" json:"user" xml:"user"  binding:"required"`
    Password string `form:"password" json:"password" xml:"password" binding:"required"`
}

func main() {
    router := gin.Default()

    router.LoadHTMLGlob("templates/*")

    router.GET("/login", func(c *gin.Context) {
        c.HTML(http.StatusOK, "login.tmpl", nil)
    })

    // Example for binding a HTML form (user=manu&password=123)
    router.POST("/loginForm", func(c *gin.Context) {
        var form Login

        // This will infer what binder to use depending on the content-type header.
        if err := c.ShouldBind(&form); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        c.JSON(http.StatusOK, form)
    })

    // Listen and serve on 0.0.0.0:8080
    router.Run(":8080")
}

和模板/login.tmpl:

<html>
<body>
<h1>Login</h1>
<form action="/loginForm" method="POST">
    <label>user:</label><br>
    <input type="text" name="user"><br>

    <label>password:</label><br>
    <input type="text" name="password"><br>

    <input type="submit">
</form>
</body>
</html>

关于forms - 如何为具有 gin(框架)和 golang 接口(interface)的表单制作通用表单函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55803040/

相关文章:

javascript - 我的大学 html 联系表需要帮助

javascript - PHP - 提交缺少名称属性的 HTML 表单

c# - 我可以将多维数据绑定(bind)到 C# 和 .NET 中的 DataGridView 吗?

java - 我如何保护我的类的实现不受其他开发人员的影响?

java - Java中的Iterator接口(interface)有什么好处?

javascript - jQuery 代码无法识别表单提交值

angularjs - 检查表单是否被触摸

go - 如何仅在满足某些条件的情况下才执行 `case`语句中的 `select`

ubuntu - Selenium 无法启动 - Ubuntu 14

mongodb - 如何使用 mgo 和 Go 查询具有日期范围的 MongoDB?