# 控制器
## 定义
在 orange 框架中,控制器是这样一个函数 `func(ctx *app.Context) error`,如下是典型的控制器定义
```
import (
"gitee.com/zhucheer/orange/app"
)
func Welcome(c *app.Context) error {
return c.ToJson(map[string]interface{}{
"info": "orange is a fast api framework",
})
}
```
## 请求
### 获取参数
#### URL变量参数
通过表达式定义的路由规则,如下所示
`groupName .GET("/userinfo/:uid", controller.UserInfo)`
`groupName .GET("/userinfo/*", controller.UserInfo)`
通过如下方法进行参数获取:
```
c.GetPathParam("iccid")
c.GetPathParam("*")
```
#### GET参数
通过控制的中的 Request 可以获得原始 request;使用 FormValue 即可获得 GET 参数;
~~~
c.Request().FormValue("token")
~~~
#### POST / GET 参数获取统一方案
在 orange 中通过 ***参数绑定*** 的方式可以获取 GET/POST 参数,参数绑定方式能获取表单提交类型的参数和json类型的参数,兼容性较好。
参数绑定方法如下:
```
// 这两个方法是等效的,主要是考虑到 gin 框架中的命名习惯
c.ShouldBind(&req)
c.ParseForm(&req)
```
具体代码如下:
```
...
func Welcome(c *app.Context) error {
req := struct {
Id int `json:"id"`
}{}
err := c.ShouldBind(&req)
if err != nil {
return c.ResponseWrite([]byte("参数解析错误"))
}
...
}
...
```
通过参数绑定可以使用 golang 结构体 tag 配置框架自带的的内置过滤器对参数收尾空白字符进行过滤:
```
// 该方式获取的参数会自动对参数首位空白字符进行过滤
req := struct {
VideoLink string `json:"videoLink" expr:"trim"`
}{}
err := c.ParseForm(&req)
```
> 注意:请求参数中包含&、>、<等特殊符号时需要进行 urlencode 编码,通过参数绑定后会自动进行 urldecode 解码;
> 例如传递参数是一个 url 时,需要对该参数进行 urlencode 后传入。
### 请求响应
Orange 对原生http响应进行了封装,有如下方法快速处理http响应
- c.ResponseWrite([]byte) 输出原始响应内容
- c.ResponseHeader() 配置/获取响应头
- c.ToJson(interface{}) 以json的方式输出响应
- c.ToString(string) 以字符串的方式输出响应
- c.ToFile("./storage/file.txt", "fileName") 以文件流方式输出一个文件,浏览器会提示下载文件
- c.ToImage("./storage/logo.png") 以文件流方式输出一个图片,浏览器会直接显示该图片
代码参考
```
...
func Welcome(c *app.Context) error {
return c.ResponseWrite([]byte("欢迎访问orange框架"))
...
}
func WelcomeJson(c *app.Context) error {
return c.ToJson(map[string]interface{}{
"info": "orange is a fast api framework",
})
}
func WelcomeText(c *app.Context) error {
c.ResponseHeader().Set("Content-Type","application/text")
return c.ToString( "orange is a fast api framework")
}
...
```
### 控制器异步后置操作
在特定的业务中,我们可能需要在请求正常返回后进行一些用户不可见的处理逻辑;
例如:后台业务中的行为记录,批量插入异步处理等等;
Orange 框架提供了后置操作的能力;使用如下:
```
// 控制器方法
func Welcome(c *app.Context) error {
// 添加一个后置执行方法,包含一个执行方法和一个延时时间两个参数
c.AddDelayAfterDo(func(ctx *app.Context) {
fmt.Println(string(ctx.ResponseBody()), ctx.OrangeInput.IP())
}, time.Second)
return c.ToString("hello world!")
}
```