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

路由控制

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"] = "MainController@gmail.com"
	// 设置要渲染的模板
	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"] = "MainController@gmail.com"
	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"] = "MainController@gmail.com"
	c.TplName = "index.tpl"
}

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

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

func (c *AddController) Get() {
	c.Data["Website"] = "AddController"
	c.Data["Email"] = "AddController@gmail.com"
	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"] = "MainController@gmail.com"
	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"] = "MainController@gmail.com"
	// 设置要渲染的模板
	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"] = "MainController@gmail.com"
	c.TplName = "index.tpl"
}

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值