GoFrame第三天

简介: GoFrame第三天

GoFrame day3


前言


上一次总结了路由相关的内容,今天就接着继续总结.当我们访问某个api的时候往往需要根据路由请求带有的参数来实现内部的操作,所以来看看怎么获得参数以及进行数据返回.


请求输入


我们在路由注册的时候都依靠ghttp.Request对象来实现页面操作处理,我们也可以通过这个对象的方法获得请求参数.


image.png


ghttp_request_param.go中可以看到相关的方法,并且看源码中所有的值都是...interface{}也就是最近推出的any,使得每个解析出来的参数值都是泛型变量.最简单的获取路由参数例子如下


package main
import (
  "github.com/gogf/gf/v2/frame/g"
  "github.com/gogf/gf/v2/net/ghttp"
)
func main() {
  s := g.Server()
  s.BindHandler("/", func(r *ghttp.Request) {
    r.Response.Writeln(r.Get("xxx").String())
  })
  s.SetPort(8080)
  s.Run()
}
复制代码


image.png


复杂参数


当我们请求的参数较为复杂时,对应不同的情况会有不同的解析结果,下面就是各种情况的总结


参数 结果
k=m&k=n map[k:n]
k1=m&k2=n map[k1:m k2:n]
k[]=m&k[]=n map[k:[m n]]
k[a][]=m&k[a][]=n map[k:map[a:[m n]]]
k[a]=m&k[b]=n map[k:map[a:m b:n]]
k[a][a]=m&k[a][b]=n map[k:map[a:map[a:m b:n]]]
k=m&k[a]=n error


对象处理


一般将输入输出定义为结构体对象,并且提交的参数可以很好的映射到预先定义的结构体属性上.默认的转换规则如下

  1. struct中需要匹配的属性必须为**公开属性**(首字母大写)。
  2. 参数名称会自动按照 不区分大小写忽略-/_/空格符号 的形式与struct属性进行匹配。
  3. 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值。

当然我们为了简单也可以自定义参数的映射规则,使用aaa typename p:"xxx"可以将xxx映射到结构体aaa属性上


package main
import (
  "github.com/gogf/gf/v2/frame/g"
  "github.com/gogf/gf/v2/net/ghttp"
)
type RegisterReq struct {
  Name  string
  Pass  string `p:"password1"`
  Pass2 string `p:"password2"`
}
type RegisterRes struct {
  Code  int         `json:"code"`
  Error string      `json:"error"`
  Data  interface{} `json:"data"`
}
func main() {
  s := g.Server()
  s.BindHandler("/register", func(r *ghttp.Request) {
    var req *RegisterReq
    if err := r.Parse(&req); err != nil {
      r.Response.WriteJsonExit(RegisterRes{
        Code:  1,
        Error: err.Error(),
      })
    }
    // ...
    r.Response.WriteJsonExit(RegisterRes{
      Data: req,
    })
  })
  s.SetPort(8080)
  s.Run()
}
复制代码


image.png


请求校验


GoFrame有强大的请求校验功能,可以给我们定义的结构体绑定v标签来实现参数校验.但是貌似这里有个bug问题,如果我们利用自定义的swagger加上v标签校验的话就会导致验证错误,无法使用try it out.当然也有其他人遇到了这个问题,具体可以看看这个issue,目前这个bug已经在2.1.0-rc4中被修复,希望下一个版本的GoFrame能更加完美.


默认值


当我们需要设置默认值的时候,可以在结构体的属性中添加d标签


数据返回


当我们处理完请求参数,可以利用请求参数实现一些逻辑,但是最终还是要返回结果给页面,这个时候就需要利用一些数据返回接口了.


缓冲控制


Response输出采用了缓冲控制,输出的内容预先写入到一块缓冲区,等待服务方法执行完毕后才真正地输出到客户端。该特性在提高执行效率同时为输出内容的控制提供了更高的灵活性。


当服务出现异常时,通常需要将错误信息对用户隐藏,转而设置为统一的错误信息,这个时候可以利用中间件的后置处理,将异常信息清除并转为提示信息输出


package main
import (
  "net/http"
  "github.com/gogf/gf/v2/frame/g"
  "github.com/gogf/gf/v2/net/ghttp"
)
func MiddlewareErrorHandler(r *ghttp.Request) {
  r.Middleware.Next()
  if r.Response.Status >= http.StatusInternalServerError {
    r.Response.ClearBuffer()
    r.Response.Writeln("服务器居然开小差了,请稍后再试吧!")
  }
}
func main() {
  s := g.Server()
  s.Group("/api.v2", func(group *ghttp.RouterGroup) {
    group.Middleware(MiddlewareErrorHandler)
    group.ALL("/user/list", func(r *ghttp.Request) {
      panic("db error: sql is xxxxxxx")
    })
  })
  s.SetPort(8080)
  s.Run()
}


image.png



当然也可以试试清除缓冲区和不清除缓冲区的区别


重定向


更多时候需要实现一些页面跳转功能,这个时候就需要用到重定向.

  • RedirectTo()可以将页面重定向到另外一个路由
  • RedirectBack()返回上一个页面

下面就简单实现一个页面跳转的demo


package main
import (
  "github.com/gogf/gf/v2/frame/g"
  "github.com/gogf/gf/v2/net/ghttp"
)
func main() {
  s := g.Server()
  s.BindHandler("/", func(r *ghttp.Request) {
    r.Response.RedirectTo("/login")
  })
  s.BindHandler("/login", func(r *ghttp.Request) {
    r.Response.Writeln(`<a href="/home">Redirect to home</a>`)
  })
  s.BindHandler("/home", func(r *ghttp.Request) {
    r.Response.Writeln(`<a href="/login">Back to login</a>`)
    //r.Response.RedirectBack()
  })
  s.SetPort(8080)
  s.Run()
}
复制代码


可以试试加与不加RedirectBack()的效果


文件下载


可以使用ServeFileServeFileDownload分别实现文件展示,文件格式识别与下载


package main
import (
  "github.com/gogf/gf/v2/frame/g"
  "github.com/gogf/gf/v2/net/ghttp"
)
func main() {
  s := g.Server()
  s.BindHandler("/show", func(r *ghttp.Request) {
    r.Response.ServeFile("test.txt")
  })
  s.BindHandler("/download", func(r *ghttp.Request) {
    r.Response.ServeFileDownload("test.txt")
  })
  s.SetPort(8080)
  s.Run()
}


image.png

下载页面会直接弹出文件下载框,大家可以自己访问看效果


最后


今天这里总结了大部分的常用处理,但是留了一个小坑—文件上传部分的内容留到下次单独讲.


目录
相关文章
|
6月前
|
存储 关系型数据库 MySQL
|
6月前
|
存储 关系型数据库 MySQL
javaweb实训第四天上午——MySQL基础(2)
3.2 启动和连接MySQL 3.2.1 启动MySQL服务
96 0
|
6月前
|
存储 SQL 关系型数据库
javaweb实训第四天上午——MySQL基础(3)
4.3 表的操作 4.3.1 创建表 语法:
109 0
|
6月前
|
SQL NoSQL 关系型数据库
javaweb实训第四天上午——MySQL基础(1)
1 课程介绍 1.数据库概述(了解) 2.MySQL的安装与配置(掌握) 3.MySQL数据库操作与存储引擎(掌握) 4.查询操作-单表查询(掌握) 2 数据库概述 2.1 数据库概念
72 0
|
存储 NoSQL Java
GoFrame避坑指南和实践干货(2)
用GoFrame已经开发了一段时间,今天为大家分享避坑指南和实践干货。这些坑并不是框架设计者的问题,更多的是我作为初学者的各种摸石头过河
215 0
GoFrame避坑指南和实践干货(2)
GoFrame第四天
GoFrame第四天
226 0
GoFrame第四天
|
安全 NoSQL 数据库连接
GoFrame第五天
GoFrame第五天
240 0
GoFrame第五天
|
缓存 中间件 API
GoFrame第二天
GoFrame第二天
305 0
GoFrame第二天
|
Ubuntu 中间件 Go
GoFrame第一天
GoFrame第一天
203 0
GoFrame第一天
|
数据库
GoFrame避坑指南和实践干货
生成的dao文件和同事们的不一致,生成文件成功,但是对应的Columns是空的,虽然有这个方法,但是方法内没有值。我的版本比同事们的略高,我一直以为是这个原因,各种降级和同事保持一致的版本后还是不行。
150 0