从零开始实现一个 GoWeb MVC 框架:让你更深入地理解 MVC 架构设计

青旅半醒 2024-03-31 10:08 89阅读 0赞

1、什么是 MVC

M 即 Model 模型是指模型表示业务规则。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

V 即 View 视图是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。MVC的好处之一在于它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操作的方式。

C 即 Controller 控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

2、Iris 简介

Iris 是使用 Go 语言开发的一个 Web 开发框架,特点有 飞快 (fast)、简单 (simple)、效率 (efficient)、小巧 (micro),该框架用起来比较顺手,虽然也存在诸多的问题,但瑕不掩瑜。

Iris 对 MVC (Model View Controller) 模式有着非常好的支持,这是其它 go 语言框架所不具备。

Iris Web 框架支持以最快的方式执行,请求数据、模型、持久性数据和绑定。

想深入了解和学习的可以参考:Iris 框架中文文档

3、项目目录

首先分享一个项目目录,先了解每个文件夹干什么
在这里插入图片描述
接下来创建一个 go 项目,示例:go-iris 并按上图目录创建所需文件夹。注意:项目目录也可以按照自己习惯创建并不是唯一

最终项目结构如下图所示

在这里插入图片描述

4、编写代码

注意:conf 和 app/model 目录此项目可忽略,暂时没用上

4.1、安装软件包

在 VS Code 终端输入以下命令并执行

  1. # 1、下载并安装 Iris,目前此项目只需要安装这一个
  2. go get -u github.com/kataras/iris/v12@master

4.2、编写代码

工欲善其事,必先利其器,我们从工具包开始

4.2.1、通用响应结构

在 utils/common 目录新建文件 response.go,完整代码如下:

  1. package common
  2. import "strconv"
  3. /**
  4. * <h1>通用响应结构体定义</h1>
  5. * Created by woniu
  6. */
  7. type CommonResponse struct {
  8. Code int `json:"code"` // 响应状态:0成功 其他失败
  9. Message string `json:"message"` // 响应消息
  10. Data interface{
  11. } `json:"data"` // 响应数据
  12. }
  13. /*
  14. * <h2>响应成功</h2>
  15. * @param data 响应数据
  16. **/
  17. func ResponseSuccess(data interface{
  18. }) CommonResponse {
  19. return CommonResponse{
  20. Code: 0,
  21. Message: "操作成功",
  22. Data: data,
  23. }
  24. }
  25. /*
  26. * <h2>响应失败</h2>
  27. * @param code 响应异常状态
  28. * @param message 响应异常消息
  29. **/
  30. func ResponseError(code int, message string) CommonResponse {
  31. return CommonResponse{
  32. Code: code,
  33. Message: message,
  34. Data: nil,
  35. }
  36. }
  37. /*
  38. * <h2>响应失败</h2>
  39. * @param code 响应异常状态
  40. **/
  41. func ResponseErrorCode(code int) CommonResponse {
  42. return CommonResponse{
  43. Code: code,
  44. Message: "操作失败",
  45. Data: nil,
  46. }
  47. }
  48. /*
  49. * <h2>响应失败</h2>
  50. * @param message 响应异常消息
  51. * 可以传入 0000_XXXXXXX 字符串,自动转换
  52. **/
  53. func ResponseErrorMessage(message string) CommonResponse {
  54. // 异常消息长度大于4
  55. if len(message) > 4 {
  56. // 截取异常消息前四位
  57. var codeStr = message[0:4]
  58. // 前四位字符串类型转 int 类型
  59. code, err := strconv.Atoi(codeStr)
  60. // 如果没有异常,自动分割,示例:0000_XXXXXXX
  61. if err == nil {
  62. return CommonResponse{
  63. Code: code,
  64. Message: message[5:],
  65. Data: nil,
  66. }
  67. }
  68. }
  69. return CommonResponse{
  70. Code: -1,
  71. Message: message,
  72. Data: nil,
  73. }
  74. }

4.2.2、业务异常自定义

在 utils/constant 目录新建文件 errors.go,完整代码如下:

  1. package constant
  2. import "errors"
  3. /**
  4. * <h1>业务异常自定义</h1>
  5. * Created by woniu
  6. */
  7. var (
  8. ResErrSysUserPasswordErr = errors.New("1003_密码错误")
  9. ResErrSysUserIsNil = errors.New("1004_用户不存在")
  10. )

4.2.3、用户登录功能

简单实现用户登录请求并正确响应,用户账号:admin,用户密码:123456

4.2.3.1、用户登录请求结构

在 app/dto 目录新建文件 login_dto.go,完整代码如下:

  1. package dto
  2. // 用户登录
  3. type LoginDto struct {
  4. Account string // 用户账号
  5. Password string // 用户密码
  6. }
4.2.3.2、系统用户响应结构

在 app/vo 目录新建文件 sys_user_vo.go,完整代码如下:

  1. package vo
  2. // 系统用户信息
  3. type SysUser struct {
  4. Account string `json:"account"` // 用户账号
  5. Name string `json:"name"` // 用户姓名
  6. Age int `json:"age"` // 用户年龄
  7. }
4.2.3.3、系统用户业务处理

在 app/service 目录新建文件 sys_user_service.go,完整代码如下:

  1. package service
  2. import (
  3. "go-iris/app/dto"
  4. "go-iris/app/vo"
  5. "go-iris/utils/constant"
  6. )
  7. /**
  8. * <h1>系统用户业务处理</h1>
  9. * Created by woniu
  10. */
  11. var SysUser = new(sysUserService)
  12. type sysUserService struct{
  13. }
  14. /**
  15. * <h2>用户名密码登录</h2>
  16. */
  17. func (s *sysUserService) PasswordLogin(requestModel dto.LoginDto) (*vo.SysUser, error) {
  18. // 用户账号必须是 admin
  19. if requestModel.Account != "admin" {
  20. return nil, constant.ResErrSysUserIsNil
  21. }
  22. // 用户密码必须是 123456
  23. if requestModel.Password != "123456" {
  24. return nil, constant.ResErrSysUserPasswordErr
  25. }
  26. // 用户名 + 密码 校验正确,返回用户信息
  27. var sysUser = vo.SysUser{
  28. Account: "admin",
  29. Name: "小明",
  30. Age: 18,
  31. }
  32. return &sysUser, nil
  33. }
4.2.3.4、系统用户控制器

在 app/controller 目录新建文件 sys_user_controller.go,完整代码如下:

  1. package controller
  2. import (
  3. "go-iris/app/dto"
  4. "go-iris/app/service"
  5. "go-iris/utils/common"
  6. "github.com/kataras/iris/v12"
  7. )
  8. /**
  9. * <h1>系统用户控制器</h1>
  10. * Created by woniu
  11. */
  12. var SysUser = new(SysUserController)
  13. type SysUserController struct{
  14. }
  15. /**
  16. * <h2>用户名密码登录</h2>
  17. */
  18. func (sc *SysUserController) PasswordLogin(ctx iris.Context) {
  19. // 登录参数
  20. var requestModel dto.LoginDto
  21. // 参数绑定
  22. if err := ctx.ReadForm(&requestModel); err != nil {
  23. ctx.JSON(common.ResponseError(-1, "传参异常"))
  24. return
  25. }
  26. // 用户登录
  27. sysUser, err := service.SysUser.PasswordLogin(requestModel)
  28. if err != nil {
  29. // 响应失败
  30. ctx.JSON(common.ResponseErrorMessage(err.Error()))
  31. return
  32. }
  33. // 响应成功
  34. ctx.JSON(common.ResponseSuccess(sysUser))
  35. }

4.2.4、通用响应测试

在 app/controller 目录新建文件 error_controller.go,完整代码如下:

  1. package controller
  2. import (
  3. "go-iris/utils/common"
  4. "github.com/kataras/iris/v12"
  5. )
  6. /**
  7. * <h1>通用响应测试控制器</h1>
  8. * Created by woniu
  9. */
  10. var Error = new(ErrorController)
  11. type ErrorController struct{
  12. }
  13. /**
  14. * <h2>响应失败</h2>
  15. */
  16. func (sc *ErrorController) ResponseError(ctx iris.Context) {
  17. // 响应失败
  18. ctx.JSON(common.ResponseError(9001, "自定义响应状态和异常消息"))
  19. }
  20. /**
  21. * <h2>响应失败</h2>
  22. */
  23. func (sc *ErrorController) ResponseErrorCode(ctx iris.Context) {
  24. // 响应失败
  25. ctx.JSON(common.ResponseErrorCode(9002))
  26. }
  27. /**
  28. * <h2>响应失败</h2>
  29. */
  30. func (sc *ErrorController) ResponseErrorMessage(ctx iris.Context) {
  31. // 响应失败
  32. ctx.JSON(common.ResponseErrorMessage("自定义响应异常消息"))
  33. }

4.2.5、请求路由

在 router 目录新建文件 router.go,完整代码如下:

  1. package router
  2. import (
  3. // 自己业务 controller 路径
  4. "go-iris/app/controller"
  5. "github.com/kataras/iris/v12"
  6. )
  7. /**
  8. * <h2>注册路由</h2>
  9. */
  10. func RegisterRouter(app *iris.Application) {
  11. // 系统用户
  12. login := app.Party("/sysUser")
  13. {
  14. // 用户名 + 密码登录
  15. login.Post("/passwordLogin", controller.SysUser.PasswordLogin)
  16. }
  17. // 通用异常
  18. err := app.Party("/error")
  19. {
  20. err.Get("/responseError", controller.Error.ResponseError)
  21. err.Get("/responseErrorCode", controller.Error.ResponseErrorCode)
  22. err.Get("/responseErrorMessage", controller.Error.ResponseErrorMessage)
  23. }
  24. }

4.2.6、自定义请求 404 响应页面

在 app/views/html 目录新建文件 404.html,完整代码如下:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>GO - IRIS</title>
  6. </head>
  7. <body>
  8. <h1 align="center">404</h1>
  9. </body>
  10. </html>

4.2.7、应用程序启动

在项目根目录新建文件 main.go,完整代码如下:

  1. package main
  2. import (
  3. "go-iris/router"
  4. "github.com/kataras/iris/v12"
  5. "github.com/kataras/iris/v12/middleware/logger"
  6. "github.com/kataras/iris/v12/middleware/recover"
  7. )
  8. /**
  9. * <h1>应用程序启动</h1>
  10. * Created by woniu
  11. */
  12. func main() {
  13. // 创建 Iris
  14. app := iris.New()
  15. // 设置调试模式
  16. app.Logger().SetLevel("debug")
  17. // 可选项添加两个内置的句柄(handlers)
  18. // 捕获相对于http产生的异常行为
  19. app.Use(recover.New())
  20. // 记录请求日志
  21. app.Use(logger.New())
  22. // 路由注册
  23. router.RegisterRouter(app)
  24. // 加载视图模板地址
  25. app.RegisterView(iris.HTML("app/views", ".html"))
  26. // 请求异常
  27. app.OnErrorCode(iris.StatusNotFound, notFound)
  28. // 监听并启动 8080 端口
  29. app.Run(iris.Addr(":8080"))
  30. }
  31. /**
  32. * <h1>请求地址不存在,跳转到 404 页面</h1>
  33. */
  34. func notFound(ctx iris.Context) {
  35. // 出现 404 的时候,就跳转到 $views_dir/html/404.html 模板
  36. ctx.View("html/404.html")
  37. }

相关代码已完成编写,最终项目结构及文件如下图

在这里插入图片描述

5、启动并测试

5.1、启动项目

在 VS Code 终端输入以下命令并执行

  1. # 启动项目
  2. go run main.go

有以下信息代表启动成功

  1. Iris Version: 12.2.0-beta6
  2. Now listening on: http://localhost:8080
  3. Application started. Press CTRL+C to shut down.

5.2、测试接口

5.2.1、用户登录

account = admin1,用户不存在

在这里插入图片描述
password = 111111,密码错误

在这里插入图片描述
account = admin 并且 password = 123456,响应成功

在这里插入图片描述

5.2.2、通用响应异常测试

自定义响应状态和异常消息

在这里插入图片描述

自定义响应状态

在这里插入图片描述

自定义响应异常消息

在这里插入图片描述

5.2.3、请求地址不存在

例如:http://localhost:8080/woniu

在这里插入图片描述

通过上述测试验证,项目达到预期目标,小伙伴自己赶紧动手试试吧。

6、每日一记

6.1、首字母大小写控制访问权限

Go语言通过首字母的大小写来控制访问权限。无论是方法,变量,常量或是自定义的变量类型,如果首字母大写,则可以被外部包访问,反之则不可以。

而结构体中的字段名,如果首字母小写的话,则该字段无法被外部包访问和解析,比如,json解析。

6.2、Json 解析首字母大写问题

如果系统用户信息结构如下:

  1. // 系统用户信息
  2. type SysUser struct {
  3. Account string // 用户账号
  4. Name string // 用户姓名
  5. Age int // 用户年龄
  6. }

请求响应结果

  1. {
  2. "code": 0,
  3. "message": "操作成功",
  4. "data": {
  5. "Account": "admin",
  6. "Name": "小明",
  7. "Age": 18
  8. }
  9. }

如果希望,Json 化之后的属性名是小写字母的,可以使用 struct tag。如下:

  1. // 系统用户信息
  2. type SysUser struct {
  3. Account string `json:"account"` // 用户账号
  4. Name string `json:"name"` // 用户姓名
  5. Age int `json:"age"` // 用户年龄
  6. }

本文教程到此结束,有问题欢迎大家讨论。

实践是检验真理的唯一标准,一键送三连关注不迷路。

发表评论

表情:
评论列表 (有 0 条评论,89人围观)

还没有评论,来说两句吧...

相关阅读

    相关 MVC框架MVC架构设计

    尽管MVC早已不是什么新鲜话题了,但是从近些年一些优秀MVC框架的设计上,我们还是会发现MVC在架构设计上的一些新亮点。本文将对传统MVC架构中的一些弊病进行解读,了