MVC 示例 - 图1

使用 iris MVC 来重用代码。

通过创建彼此独立的组件,开发人员可以在其他应用程序中快速轻松地重用组件。一个程序相同或者相似的视图可以被其他应用使用不同的数据重构,因为视图把数据展示给用户的做法都相似。

Iris对MVC(模型视图控制器)架构模式提供了一流的支持,在Go世界中其他任何地方都找不到这些东西。 您将必须导入 iris/mvc 子包。

  1. import "github.com/kataras/iris/v12/mvc"

Iris web 框架支持请求数据,模型,持续性数据和最快的执行速度绑定。

如果您不熟悉后端Web开发,请先阅读有关MVC架构模式的文章,这是一个不错的开始。

特点(Characteristics)

支持所有的 HTTP 状态码,例如,如果想要处理 GET方法,控制器需要有一个名为 Get() 的函数,你可以在一个控制器中定义多个方法来处理请求。

通过每个控制器的 BeforeActivation 自定义事件回调,将自定义控制器的struct方法用作具有自定义路径(甚至带有 regex 参数化路径)的处理程序。 例:

  1. import (
  2. "github.com/kataras/iris/v12"
  3. "github.com/kataras/iris/v12/mvc"
  4. )
  5. func main() {
  6. app := iris.New()
  7. mvc.Configure(app.Party("/root"), myMVC)
  8. app.Run(iris.Addr(":8080"))
  9. }
  10. func myMVC(app *mvc.Application) {
  11. // app.Register(...)
  12. // app.Router.Use/UseGlobal/Done(...)
  13. app.Handle(new(MyController))
  14. }
  15. type MyController struct {}
  16. func (m *MyController) BeforeActivation(b mvc.BeforeActivation) {
  17. // b.Dependencies().Add/Remove
  18. // b.Router().Use/UseGlobal/Done
  19. // and any standard Router API call you already know
  20. // 1-> Method
  21. // 2-> Path
  22. // 3-> The controller's function name to be parsed as handler
  23. // 4-> Any handlers that should run before the MyCustomHandler
  24. b.Handle("GET", "/something/{id:long}", "MyCustomHandler", anyMiddleware...)
  25. }
  26. // GET: http://localhost:8080/root
  27. func (m *MyController) Get() string {
  28. return "Hey"
  29. }
  30. // GET: http://localhost:8080/root/something/{id:long}
  31. func (m *MyController) MyCustomHandler(id int64) string {
  32. return "MyCustomHandler says Hey"
  33. }

通过为依赖项定义服务或者有一个 Singleton 控制器作用域, 在你的控制器结构体中持续性数据(在两个请求间分享数据)。

在控制器间分享依赖或者将它们注册到一个父MVC程序中,有能力在每个控制器的 BeforeActivate 可选事件回调函数中修改依赖,例如:

  1. func(c *MyController) BeforeActivation(b mvc.BeforeActivation) {
  2. b.Dependencies().Add/Remove(...)
  3. }

作为控制器的字段来访问 Context(无需手动绑定),即 Ctx iris.Context 或者通过一个方法的输出参数,即 func(ctx iris.Context, otherArguments)

控制器结构体内部的模型(在方法函数中设置,并通过视图渲染)。你可以从一个控制器的方法中返回模型,或者在请求的声明周期中设置一个字段,在同一个请求的生命周期中的另一个方法中返回这个字段。

就像你以前使用的流程一样,MVC 程序有自己的 Router,这是 iris/router.Party 类型的,标准的 iris api Controllers 可以被注册到任何 Party 中,包括子域名,Party 的开始和完成处理器与预期的一样工作。

可选的 BeginRequest(ctx) 函数,用于在方法执行之前执行任何初始化,这对调用中间件或许多方法使用相同的数据收集很有用。

可选的 EndRequest(ctx)函数, 可在执行任何方法之后执行任何终结处理。

递归继承,例如 我们的mvc会话控制器示例具有 Session * sessions.Session 作为字段,由会话管理器的 Start 填充为MVC应用程序的动态依赖项:mvcApp.Register(sessions.New(sessions.Config{Cookie:"iris_session_id"}).Start

通过控制器方法的输入参数访问动态路径参数,不需要绑定。当你使用 Iris 的默认语法从一个控制器中解析处理器,你需要定义方法的后缀为 By,大写字母是新的子路径。例如:

如果 mvc.New(app.Party("/user")).Handle(new(user.Controller))

  • func(*Controller) Get() - GET:/user
  • func(*Controller) Post() - POST:/user
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

如果 mvc.New(app.Party("/profile")).Handle(new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

如果 mvc.New(app.Party("/assets")).Handle(new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

方法函数接受的类型可以为:intint64boolstring

可选的响应输出参数,就像我们前面看到的一样:

  1. func(c *ExampleController) Get() string |
  2. (string, string) |
  3. (string, int) |
  4. int |
  5. (int, string) |
  6. (string, error) |
  7. error |
  8. (int, error) |
  9. (any, bool) |
  10. (customStruct, error) |
  11. customStruct |
  12. (customStruct, int) |
  13. (customStruct, string) |
  14. mvc.Result or (mvc.Result, error)

这里的 mvc.Resulthero.Result 的别名,就是这个接口:

  1. type Result interface {
  2. // Dispatch should sends the response to the context's response writer.
  3. Dispatch(ctx iris.Context)
  4. }

示例

这个例子相当于: https://github.com/kataras/iris/blob/master/_examples/hello-world/main.go

这看起来像多于的代码,不值得书写,但是记住,这个实例没有使用 Iris MVC 的模型,持续化或者视图引擎等特性,没有使用 Session,这仅仅是为了学习,或许你在你的程序中不会使用如此简单的控制器。

在这个实例中,在 /hello 路径下使用 MVC时,我的个人电脑的消耗是没20MB吞吐大于是2MB,这对于大多数应用程序都可以容忍,但是你可以选择iris中最适合你的,低级处理器的性能或高级控制器:易于维护,大型应用程序上的代码库较小。

仔细阅读注释

  1. package main
  2. import (
  3. "github.com/kataras/iris/v12"
  4. "github.com/kataras/iris/v12/mvc"
  5. "github.com/kataras/iris/v12/middleware/logger"
  6. "github.com/kataras/iris/v12/middleware/recover"
  7. )
  8. func main() {
  9. app := iris.New()
  10. // Optionally, add two built'n handlers
  11. // that can recover from any http-relative panics
  12. // and log the requests to the terminal.
  13. app.Use(recover.New())
  14. app.Use(logger.New())
  15. // Serve a controller based on the root Router, "/".
  16. mvc.New(app).Handle(new(ExampleController))
  17. // http://localhost:8080
  18. // http://localhost:8080/ping
  19. // http://localhost:8080/hello
  20. // http://localhost:8080/custom_path
  21. app.Run(iris.Addr(":8080"))
  22. }
  23. // ExampleController serves the "/", "/ping" and "/hello".
  24. type ExampleController struct{}
  25. // Get serves
  26. // Method: GET
  27. // Resource: http://localhost:8080
  28. func (c *ExampleController) Get() mvc.Result {
  29. return mvc.Response{
  30. ContentType: "text/html",
  31. Text: "<h1>Welcome</h1>",
  32. }
  33. }
  34. // GetPing serves
  35. // Method: GET
  36. // Resource: http://localhost:8080/ping
  37. func (c *ExampleController) GetPing() string {
  38. return "pong"
  39. }
  40. // GetHello serves
  41. // Method: GET
  42. // Resource: http://localhost:8080/hello
  43. func (c *ExampleController) GetHello() interface{} {
  44. return map[string]string{"message": "Hello Iris!"}
  45. }
  46. // BeforeActivation called once, before the controller adapted to the main application
  47. // and of course before the server ran.
  48. // After version 9 you can also add custom routes for a specific controller's methods.
  49. // Here you can register custom method's handlers
  50. // use the standard router with `ca.Router` to
  51. // do something that you can do without mvc as well,
  52. // and add dependencies that will be binded to
  53. // a controller's fields or method function's input arguments.
  54. func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) {
  55. anyMiddlewareHere := func(ctx iris.Context) {
  56. ctx.Application().Logger().Warnf("Inside /custom_path")
  57. ctx.Next()
  58. }
  59. b.Handle(
  60. "GET",
  61. "/custom_path",
  62. "CustomHandlerWithoutFollowingTheNamingGuide",
  63. anyMiddlewareHere,
  64. )
  65. // or even add a global middleware based on this controller's router,
  66. // which in this example is the root "/":
  67. // b.Router().Use(myMiddleware)
  68. }
  69. // CustomHandlerWithoutFollowingTheNamingGuide serves
  70. // Method: GET
  71. // Resource: http://localhost:8080/custom_path
  72. func (c *ExampleController) CustomHandlerWithoutFollowingTheNamingGuide() string {
  73. return "hello from the custom handler without following the naming guide"
  74. }
  75. // GetUserBy serves
  76. // Method: GET
  77. // Resource: http://localhost:8080/user/{username:string}
  78. // By is a reserved "keyword" to tell the framework that you're going to
  79. // bind path parameters in the function's input arguments, and it also
  80. // helps to have "Get" and "GetBy" in the same controller.
  81. //
  82. // func (c *ExampleController) GetUserBy(username string) mvc.Result {
  83. // return mvc.View{
  84. // Name: "user/username.html",
  85. // Data: username,
  86. // }
  87. // }
  88. /* Can use more than one, the factory will make sure
  89. that the correct http methods are being registered for each route
  90. for this controller, uncomment these if you want:
  91. func (c *ExampleController) Post() {}
  92. func (c *ExampleController) Put() {}
  93. func (c *ExampleController) Delete() {}
  94. func (c *ExampleController) Connect() {}
  95. func (c *ExampleController) Head() {}
  96. func (c *ExampleController) Patch() {}
  97. func (c *ExampleController) Options() {}
  98. func (c *ExampleController) Trace() {}
  99. */
  100. /*
  101. func (c *ExampleController) All() {}
  102. // OR
  103. func (c *ExampleController) Any() {}
  104. func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) {
  105. // 1 -> the HTTP Method
  106. // 2 -> the route's path
  107. // 3 -> this controller's method name that should be handler for that route.
  108. b.Handle("GET", "/mypath/{param}", "DoIt", optionalMiddlewareHere...)
  109. }
  110. // After activation, all dependencies are set-ed - so read only access on them
  111. // but still possible to add custom controller or simple standard handlers.
  112. func (c *ExampleController) AfterActivation(a mvc.AfterActivation) {}
  113. */

在控制器中每个以HTTP方法(GetPostPutDelete…) 为前缀的函数,都作为一个 HTTP 端点。在上面的示例中,所有的函数都向响应写了一个字符串。注意每种方法之前的注释。

一个HTTP端点在web程序中是可定位的URL,例如 http://localhost:8080/helloworld,结合使用的协议:HTTP,web服务器的网络定位(包括TCP端口):localhost:8080 和 定位的URI:/helloworld

第一个注释指出这是一个HTTP GET方法,该方法通过在基本URL后面附加/helloworld 来调用。第三条注释指定HTTP GET方法,该方法通过在URL后面附加 /helloworld/welcome 来调用。

控制器知道怎么处理 GetBy 上的 “name” 或者 GetWelcomeBy 上的 “name” 和 “numTimes”,因为 By 关键字,并且建立了没有样板的动态路由;第三个注释指定HTTP GET动态方法,该方法可以由任何以“ / helloworld / welcome”开头的URL调用,然后再加上两个路径部分,第一个可以接受任何值,第二个只能接受数字,例如:http://localhost:8080/helloworld/welcome/golang/32719,除此以外,404 Not Found HTTP Error 将被发送到客户端。

https://github.com/kataras/iris/tree/master/_examples/mvchttps://github.com/kataras/iris/blob/master/mvc/controller_test.go 通过简单的范式解释了特性,它们展示了如何利用 Iris MVC 的 Binder、模型等等…

websocket 控制器请看前面的 Websocket 章节。