GO语言Beego框架之WEB安全小系统(2)路由跳转教程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/A657997301/article/details/82354287

路由控制

beego的路由设置有三种方式:固定路由、正则路由、自动路由。(具体可见:传送门

下面以固定路由自定义方法为例

修改视图

views/index.tpl 里的<body> 标签修改如下(添加了一个form表单和一个上传文件功能):

<body>
  <header>
    <h1 class="logo">Welcome to Beego</h1>
    <div class="description">
      Beego is a simple & powerful Go web framework which is inspired by tornado and sinatra.<br>
      Username:{{.Username}}<br>
      Age:{{.Age}}<br>
      Email:{{.Eemail}}<br>
    </div>
  </header>
  <div class="postform">
    <form id="user" action="http://127.0.0.1:8080/" method="post">
        名字:<input name="username" type="text" />
        年龄:<input name="age" type="text" />
        邮箱:<input name="Email" type="text" />
        <input type="submit" value="提交" />
    </form>
    <form enctype="multipart/form-data" action="http://127.0.0.1:8080/upload" method="post">
        <input type="file" name="uploadname" />
        <input type="submit">
    </form>
  </div>
  <footer>
    <div class="author">
      Official website:
      <a href="http://{{.Website}}">{{.Website}}</a> /
      Contact me:
      <a class="email" href="mailto:{{.Email}}">{{.Email}}</a>
    </div>
  </footer>
  <div class="backdrop"></div>

  <script src="/static/js/reload.min.js"></script>
</body>

注意:
form不指定method属性的话默认是GET,所以应该声明下method="post"。不指定action的话默认是发送请求至当前页面的url,因此还是建议指定下action

static/css/index.css 里修改如下(只是为了居中):

.description,
.postform {
    text-align: center;
    font-size: 16px;
}

然而可能有个问题,就是在重复启动项目的过程中,由于之前已经请求加载过一次css文件了,被服务器保存在缓存中,所以我们本次修改后的css文件不会被服务器更新,解决方法即在views/index.tpl 中修改如下:

<link href="../static/css/index.css?ver=1" rel="stylesheet" type="text/css" />

ver = n,n代表版本号,加一个版本号即可。

路由器

routers/router.go 里添加如下代码:

func init() {
    // 设置固定路由,指定url和对应的控制器
    beego.Router("/", &controllers.MainController{})
    beego.Router("/admin", &controllers.UserController{})
    beego.Router("/admin/index", &controllers.ArticleController{})
    beego.Router("/admin/addpkg", &controllers.AddController{})
    // 设置自定义路由,指定发送到/upload的post请求对应控制器里的UploadFile方法
    beego.Router("/upload", &controllers.MainController{}, `post:UploadFile`)
    beego.Router("/TestPostJson", &controllers.MainController{}, `post:TestPostJson`)
    beego.Router("/TestGetJson", &controllers.MainController{}, `get:TestGetJson`)
}

beego的固定路由方式是典型的 RESTful 方式:一个固定的路由,一个控制器,然后根据用户请求方法不同请求控制器中对应的方法。比如url/admin,根据上面代码,则会请求ArticleController控制器的方法。(请求的 method 和函数名一致,例如 GET 请求执行 Get 函数,POST 请求执行 Post 函数,所以只需要在控制器里重写Get方法和Post方法

而自定义路由方式,则多了beego.Router的第三个参数。冒号前面部分表示发送到urlhttp请求的method,如果是星号* 则表示所有。冒号后面表示对应匹配的方法,如post:UploadFile 表示传到该urlpost请求指定对应控制器里的UploadFile函数来处理,而*:UploadFile 表示所有传到该url的请求都用UploadFile函数来处理。

控制器

controllers/default.go 里添加如下代码(这里MainController 还重写了Post方法):

type MainController struct {
    beego.Controller
}
type UserController struct {
    beego.Controller
}

type ArticleController struct {
    beego.Controller
}

type AddController struct {
    beego.Controller
}

type user struct {
    /*
    定义 struct 时,字段名后如果有 form 这个 tag,则会以把 form 表单里的 name 和 tag 的名称一样的字段赋值给这个字段,
    否则就会把 form 表单里与字段名一样的表单内容赋值给这个字段(通过form这个tag)。
    如上面例子中,会把表单中的 username 和 age 分别赋值给 user 里的 Name 和 Age 字段,
    而 Email 里的内容则会赋给 Email 这个字段(与字段名一样的表单内容,无需form)
    */
    // 如果要忽略一个字段,有两种办法,一是:字段名小写开头,
    // 二是:form 标签的值设置为"-"。这里明显是第二种
    Id    int         `form:"-"`
    Name  interface{} `form:"username"`
    Age   int         `form:"age"`
    Email string
}

func (c *MainController) Get() {
    // c.Data["XXX"]这个map数据结构可以直接被views视图以{{.XXX}}来获取
    c.Data["Website"] = "MainController"
    c.Data["Email"] = "[email protected]"
    // 设置要渲染的模板
    c.TplName = "index.tpl"
}

func (c *MainController) Post() {
    // 新建一个user
    u := user{}
    // 接下来是为了验证以post提交的form的数据是否存储在c的Data这个map数据结构中,事实证明不是的。
    beego.Debug("\n",
        "Id:", 123, "\n",
        "Name", c.Data["Username"], "\n",
        "Age", c.Data["Age"], "\n",
        "Email",c.Data["Eemail"])
    // 将c,即MainController,里存储的数据转化到user格式的u变量,注意必须传入地址
    if err := c.ParseForm(&u); err != nil {
        log.Fatal("ParseForm err ", err)
    }
    // 现在u是个有数据的user了,取出来存到c里去
    c.Data["Username"] = u.Name
    c.Data["Age"] = u.Age
    c.Data["Eemail"] = u.Email
    // 输出u里的四个属性值
    beego.Debug("\n",
        "Id:", u.Id, "\n",
        "Name", u.Name, "\n",
        "Age", u.Age, "\n",
        "Email", u.Email, "\n")

    c.Data["Website"] = "MainController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

// 上传文件的post请求处理
func (c *MainController) UploadFile() {
    // 获取控制器数据流里的文件
    f, h, err := c.GetFile("uploadname")
    if err != nil {
        log.Fatal("getfile err ", err)
    }
    defer f.Close()
    // 保存位置在 static/upload, 没有文件夹要先创建,不然文件保存失败
    c.SaveToFile("uploadname", "static/upload/" + h.Filename)
    c.Data["Website"] = "MainController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

func (c *UserController) Get() {
    c.Data["Website"] = "UserController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

func (c *ArticleController) Get() {
    c.Data["Website"] = "ArticleController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

func (c *AddController) Get() {
    c.Data["Website"] = "AddController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

type User struct {
    Id       int
    Username string
    Password string
}

// POST JSON数据
func (c *MainController) TestPostJson() {
    ob := &User{}
    var err error
    // POST过来的数据保存在requestBody里,由于是JSON格式,使用json.Unmarshal转为ob
    if err = json.Unmarshal(c.Ctx.Input.RequestBody, &ob); err == nil {
        // 输出ob
        beego.Debug("\n",
            "Unmarshal success", "\n",
            "show Student :", "\n",
            "Id", ob.Id, "\n",
            "Username", ob.Username, "\n",
            "Password", ob.Password, "\n",
        )
        // 再把ob转为JSON数据输出,注意传进Data["json"]的数据本身不能是JSON数据
        c.Data["json"] = ob
        c.ServeJSON()
    }
    c.Data["Website"] = "MainController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

// GET JSON数据
func (c *MainController) TestGetJson() {
    ob := &User{520, "StellaChan", "19970227"}
    // 将User类型的ob使用json.Marshal转为JSON格式
    if b, err := json.Marshal(ob); err == nil {
        // 输出ob
        beego.Debug("\n",
            b, "\n",
            string(b), "\n",
            ob, "\n",
        )
        // 再把ob转为JSON数据输出,注意传进Data["json"]的数据本身不能是JSON数据
        c.Data["json"] = ob
        c.ServeJSON()
    }
}

首先我们声明了几个控制器,控制器里面内嵌了beego.Controller,这就是 Go 的嵌入方式,也就是这些控制器都自动拥有了所有 beego.Controller 的方法。

beego.Controller 拥有很多方法,其中包括 InitPreparePostGetDeleteHead 等方法。我们可以通过重写的方式来实现这些方法,而我们上面的代码就是重写了 GetPost 方法。

上述代码使用了固定路由自定义路由两种。方法里面的代码是需要执行的逻辑,我们可以通过各种方式获取数据,然后赋值到 this.Data 中,这是一个用来存储输出数据的 map 数据结构,可以赋值任意类型的值。c.Data["XXX"]这个map数据结构可以直接被views视图以{{.XXX}}来获取,语法详见beego模板语法指南:传送门

最后一个就是需要去渲染的模板,this.TplName 就是需要渲染的模板,这里指定了 index.tpl,如果用户不设置该参数,那么默认会去到模板目录的 Controller/<方法名>.tpl 查找,例如 maincontroller/get.tpl (文件、文件夹必须小写)。

用户设置了模板之后系统会自动的调用 Render 函数(这个函数是在 beego.Controller 中实现的),所以无需用户自己来调用渲染。

当然也可以不使用模版,直接用 this.Ctx.WriteString 输出字符串,如:

func (this *MainController) Get() {
        this.Ctx.WriteString("hello")
}

这样就会单纯返回一个字符串并显示。

上述代码还涉及文件上传以及一些http请求的处理逻辑,下面我们会一一再详讲。

运行

现在先启动我们的项目,记得在main函数里不要运行到上一节的数据库函数,只需要如下:

func main() {
    beego.Run()
}

普通页面请求GET

输入http://127.0.0.1:8080/
界面显示如下:
这里写图片描述

后台显示如下:
这里写图片描述

请求的host127.0.0.1url“/”methodGET,请求响应结果状态码为200,表示响应成功。

界面红框部分很明显是控制器的方法在作用:

func (c *MainController) Get() {
    // c.Data["XXX"]这个map数据结构可以直接被views视图以{{.XXX}}来获取
    c.Data["Website"] = "MainController"
    c.Data["Email"] = "[email protected]"
    // 设置要渲染的模板
    c.TplName = "index.tpl"
}

我们在路由器还有其他的url跟控制器的设置
输入 http://127.0.0.1:8080/admin
这里写图片描述

输入 http://127.0.0.1:8080/admin/index
这里写图片描述

输入 http://127.0.0.1:8080/admin/addpkg
这里写图片描述

可以看到输出与我们在控制器里的代码设置一致,程序运行正确。

POST

POST 表单

填写表单并提交:
这里写图片描述

后台输出结果如下:
这里写图片描述

第一部分的输出对应代码如下:

    beego.Debug("\n",
        "Id:", 123, "\n",
        "Name", c.Data["Username"], "\n",
        "Age", c.Data["Age"], "\n",
        "Email",c.Data["Eemail"])

这里是为了验证以post提交的表单数据,是否是存储在cData这个map数据结构中,然而可以看到输出的结果为<nil>,即为空,所以不能通过c.Data直接取数据(实际上,提交的表单数据是保存在c.Ctx.Request.Form中)

而后使用c.ParseForm(&u), 根据u的结构体构造(form 这个 tag),将表单数据保存在u中,于是就可以通过u.XX的方式提取出数据了。

之后代码如下:

    // 现在u是个有数据的user了,取出来存到c里去
    c.Data["Username"] = u.Name
    c.Data["Age"] = u.Age
    c.Data["Eemail"] = u.Email

可以看到页面的输出结果:
这里写图片描述

POST 文件

先在static文件夹里新建一个文件夹,名为upload
这里写图片描述

选择文件并提交上传:
这里写图片描述

后台输出结果如下:
这里写图片描述

可以看到文件夹里多了刚上传的文件:
这里写图片描述

beego中,如果只是单纯的文件上传的话还是很方便处理的,有c.GetFile("")c.SaveToFile("") 两个函数分别负责获取上传的文件以及保存文件。

JSON数据请求

GET JSON

输入http://127.0.0.1:8080/TestGetJson
界面显示如下:
这里写图片描述

后台显示如下:
这里写图片描述

对应代码如下:

type User struct {
    Id       int
    Username string
    Password string
}
// GET JSON数据
func (c *MainController) TestGetJson() {
    ob := &User{520, "StellaChan", "19970227"}
    // 将User类型的ob使用json.Marshal转为JSON格式
    if b, err := json.Marshal(ob); err == nil {
        // 输出ob
        beego.Debug("\n",
            b, "\n",
            string(b), "\n",
            ob, "\n",
        )
        // 把ob转为JSON数据输出,注意传进Data["json"]的数据本身不能是JSON数据
        c.Data["json"] = ob
        c.ServeJSON()
    }
}

先定义了个User结构体,然后声明一个User类型变量ob并且初始化值。其实这个时候就可以通过赋值给c.Data["json"]的方式将User类型变量obJSON格式输出到页面(或者反馈给发送了GET请求的客户端)。
中间展示的是通过json.MarshalUser类型的ob转为JSON格式的变量b此时b直接输出是ASCII码值,必须转为字符串string类型才能正常显示

POST JSON

正常网页没法做到POST,因此本人此处借助Postman来发送post请求。
先在Headers指定post的数据格式为JSON
这里写图片描述

再在Body中写入要PostJSON数据,并且点击Send
这里写图片描述

后台显示如下(可以看到成功接收了JSON数据并解析):
这里写图片描述

对应代码如下:

// POST JSON数据
func (c *MainController) TestPostJson() {
    ob := &User{}
    var err error
    // POST过来的数据保存在requestBody里,由于是JSON格式,使用json.Unmarshal转为ob
    if err = json.Unmarshal(c.Ctx.Input.RequestBody, &ob); err == nil {
        // 输出ob
        beego.Debug("\n",
            "Unmarshal success", "\n",
            "show Student :", "\n",
            "Id", ob.Id, "\n",
            "Username", ob.Username, "\n",
            "Password", ob.Password, "\n",
        )
        // 再把ob转为JSON数据输出,注意传进Data["json"]的数据本身不能是JSON数据
        c.Data["json"] = ob
        c.ServeJSON()
    }
    c.Data["Website"] = "MainController"
    c.Data["Email"] = "[email protected]"
    c.TplName = "index.tpl"
}

GET JSON类似,先声明一个User类型变量ob,然后通过json.UnmarshalJSON类型的c.Ctx.Input.RequestBody (我们前文有提到POST的数据保存在这里)转为User类型的变量ob。之后的步骤类似,最后我们再通过赋值给c.Data["json"]的方式将User类型变量obJSON格式输出到页面(或者反馈给发送了POST请求的客户端)。

猜你喜欢

转载自blog.csdn.net/A657997301/article/details/82354287