golang iris 学习一: 使用MVC模式+Mongo数据库

最近有时间,重新把Golang学习了一下,得搞点东西练练手,看着能不能用Golang Iris把Python Flask的后台重写一下,刚好golang更新了mod模式,试用一把!!!
系统环境:ubuntu18.04
golang版本:1.13
mongo: 随便docker run出来的

目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.
├── config
│   └── config.go
├── config.yml
├── controllers
│   └── game_controller.go
├── datamodels
│   ├── game.go
│   └── response.go
├── datasource
│   └── mongo.go
├── go.mod
├── go.sum
├── main.go
├── repo
│   └── game_repo.go
├── route
│   └── route.go
└── services
└── game_service.go

先定义一个模型吧,就是跟Python SQLALCHEMY的数据库结构一个道理,来个简单的走起:

datamodels目录存放数据模型

datamodels/game.go

1
2
3
4
5
6
7
8
9
package datamodels

import "gopkg.in/mgo.v2/bson"

type Game struct {
ID bson.ObjectId `json:"_id" bson:"_id"`
Name string `json:"name" bson:"name"`
GameCode string `json:"gamecode" bson:"gamecode"`
}

定义一个通用数据返回模型,返回给前端用的

datamodels/response.go

1
2
3
4
5
6
7
package datamodels

type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}

然后得连接数据库,先搞份数据库配置:

config.yml

1
2
3
4
5
6
mongo:
host: 127.0.0.1
port: 27017
user: ~
pass: ~
name: oms

然后把配置文件转成结构体

config/config.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package config

import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
)

type mongoConfig struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
User string `yaml:"user"`
Pass string `yaml:"pass"`
Name string `yaml:"name"`
}

type globalConfig struct {
Mongo mongoConfig `yaml:"mongo"`
}

var GConfig = &globalConfig{}

func init() {
yamlFile, err := ioutil.ReadFile("config.yml")
if err != nil {
panic(err)
}

err = yaml.Unmarshal(yamlFile, GConfig)
if err != nil {
log.Fatalf("Unmarshal: %v", err)
}
}

接着需要连接数据库

datasource目录存放初始化数据库连接

datasource/mongo.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package datasource

import (
"goms/config"
"gopkg.in/mgo.v2"
"log"
"time"
)

var (
session *mgo.Session
)

func init() {
dialInfo := &mgo.DialInfo{
Addrs: []string{config.GConfig.Mongo.Host},
Direct: false,
Timeout: time.Second * 60,
FailFast: false,
Database: config.GConfig.Mongo.Name,
ReplicaSetName: "",
Source: "",
Service: "",
ServiceHost: "",
Mechanism: "",
Username: "",
Password: "",
PoolLimit: 4096,
DialServer: nil,
Dial: nil,
}
sess, err := mgo.DialWithInfo(dialInfo)
if err != nil {
log.Fatal(err.Error())
}
session = sess
session.SetMode(mgo.Monotonic, true)
}

type SessionStore struct {
session *mgo.Session
}

func NewSessionStore() *SessionStore {
return &SessionStore{
session: session.Copy(),
}
}

func (s *SessionStore) C(name string) *mgo.Collection {
return s.session.DB(config.GConfig.Mongo.Name).C(name)
}

func (s *SessionStore) Close() {
s.session.Close()
}

func GetErrNotFound() error {
return mgo.ErrNotFound
}

来个CRUD操作

repo目录存放操作数据库的方法

repo/game_repo.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package repo

import (
"goms/datamodels"
"goms/datasource"
"gopkg.in/mgo.v2/bson"
)

type GamesRepository interface {
List(query map[string]interface{}) (games []datamodels.Game, err error)
Save(game datamodels.Game) (err error)
GetByID(id string) (game datamodels.Game, err error)
DeleteByID(id string) (err error)
}

type gamesRepository struct {
collection string
}

func NewGamesRepository() GamesRepository {
return &gamesRepository{
collection: "project_games",
}
}

func (g *gamesRepository) List(query map[string]interface{}) (games []datamodels.Game, err error) {
db := datasource.NewSessionStore()
defer db.Close()
col := db.C(g.collection)

if err = col.Find(nil).All(&games); err != nil {
if err.Error() != datasource.GetErrNotFound().Error() {
return
}
}
return
}

func (g *gamesRepository) Save(game datamodels.Game) (err error) {
db := datasource.NewSessionStore()
defer db.Close()
col := db.C(g.collection)

if game.ID.Hex() == "" {
game.ID = bson.NewObjectId()
err = col.Insert(game)
} else {
err = col.Update(bson.M{"_id": game.ID}, game)
}

return
}

func (g *gamesRepository) GetByID(id string) (game datamodels.Game, err error) {
db := datasource.NewSessionStore()
defer db.Close()
col := db.C(g.collection)

err = col.FindId(bson.ObjectIdHex(id)).One(&game)
return
}

func (g *gamesRepository) DeleteByID(id string) (err error) {
db := datasource.NewSessionStore()
defer db.Close()
col := db.C(g.collection)

err = col.RemoveId(bson.ObjectIdHex(id))
return
}

service目录调用repo方法得出最后的结果并整理

service/game_service.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package services

import (
"fmt"
"goms/datamodels"
"goms/repo"
)

type GameService interface {
List(m map[string]interface{}) (response datamodels.Response)
Save(game datamodels.Game) (response datamodels.Response)
GetByID(id string) (response datamodels.Response)
DeleteByID(id string) (response datamodels.Response)
}

type gameService struct {
repo repo.GamesRepository
}

var gameRepo = repo.NewGamesRepository()

func NewGameService() GameService {
return &gameService{
repo: gameRepo,
}
}

func (g *gameService) List(m map[string]interface{}) (response datamodels.Response) {
games, _ := g.repo.List(nil)
response.Code = 20000
response.Msg = "success"
response.Data = games
return
}

func (g *gameService) Save(game datamodels.Game) (response datamodels.Response) {
err := g.repo.Save(game)
if err != nil {
response.Code = 30001
response.Msg = fmt.Sprintf("保存数据失败:%v", err)
}
response.Code = 20000
response.Msg = "success"

return
}

func (g *gameService) GetByID(id string) (response datamodels.Response) {
game, err := g.repo.GetByID(id)
if err != nil {
response.Code = 30002
response.Msg = fmt.Sprintf("查询数据失败:%v", err)
}
response.Code = 20000
response.Msg = "success"
response.Data = game
return
}

func (g *gameService) DeleteByID(id string) (response datamodels.Response) {
err := g.repo.DeleteByID(id)
if err != nil {
response.Code = 30003
response.Msg = fmt.Sprintf("删除数据失败:%v", err)
}
response.Code = 20000
response.Msg = "success"
return
}

controllers响应Web请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package controllers

import (
"fmt"
"github.com/kataras/iris"
"goms/datamodels"
"goms/services"
"gopkg.in/mgo.v2/bson"
)

type GameController struct {
Ctx iris.Context
Service services.GameService
}

func NewGameController() *GameController {
return &GameController{
Service: services.NewGameService(),
}
}

func (g *GameController) Get() (response datamodels.Response) {
return g.Service.List(nil)
}

func (g *GameController) GetBy(id string) (response datamodels.Response) {
return g.Service.GetByID(id)
}

func (g *GameController) DeleteBy(id string) (response datamodels.Response) {
return g.Service.DeleteByID(id)
}

func (g *GameController) PutBy(id string) (response datamodels.Response) {
game := datamodels.Game{}
err := g.Ctx.ReadJSON(&game)
if err != nil {
response.Code = 40001
response.Msg = fmt.Sprintf("参数解析失败:%v", err)
}
game.ID = bson.ObjectIdHex(id)
return g.Service.Save(game)
}

func (g *GameController) Post() (response datamodels.Response) {
game := datamodels.Game{}
err := g.Ctx.ReadJSON(&game)
if err != nil {
response.Code = 40001
response.Msg = fmt.Sprintf("参数解析失败:%v", err)
}
return g.Service.Save(game)
}

route生成路由

route/route.go

1
2
3
4
5
6
7
8
9
10
11
12
package route

import (
"github.com/kataras/iris"
"github.com/kataras/iris/mvc"
"goms/controllers"
)

func InitRoute(app *iris.Application) {
bathPath := "/api/v1"
mvc.New(app.Party(bathPath + "/games")).Handle(controllers.NewGameController())
}

入口程序main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
//"github.com/iris-contrib/middleware/cors"
"github.com/kataras/iris"
"github.com/kataras/iris/middleware/logger"
"github.com/kataras/iris/middleware/recover"
"goms/route"
)

func newApp() *iris.Application {
app := iris.New()
app.Use(recover.New())
app.Use(logger.New())
app.AllowMethods(iris.MethodOptions)
return app
}

func main() {
app := newApp()
route.InitRoute(app)
app.Run(iris.Addr(":8080"))
}

go run跑起来~~