一、單一職責(一個服務只作一件事)html
二、服務粒度適中前端
三、考慮團隊結構mysql
四、以業務模型切入git
五、演進式拆分github
六、避免環形依賴和雙向依賴web
若是尚未安裝 beego 的話先安裝 beegoredis
$ go get -u -v github.com/astaxie/beego $ go get -u -v github.com/beego/bee $ cd $GOPATH/src/github.com/beego/bee $ go build $ sudo mv bee /bin/
項目開始以前,咱們先要啓動咱們單機版的 consulsql
$ consul agent -dev
在 mysql 中建立一個數據庫:ihomeshell
$ mysql -uroot -p # 輸入 root 密碼 # 建立1個數據庫:ihome mysql>create database if not exists ihome default charset utf8 collate utf8_general_ci;
能夠先去 Github 中提早查看一下 Web 端的文件結構::https://github.com/lpg-it/ihome/tree/master/ihomeWeb數據庫
$ cd $GOPATH/src $ micro new --type "web" ihome/ihomeWeb
package main import ( "github.com/julienschmidt/httprouter" "github.com/micro/go-log" "net/http" "github.com/micro/go-web" ) func main() { // create new web service service := web.NewService( web.Name("go.micro.web.ihomeWeb"), web.Version("latest"), web.Address(":8080"), ) // initialise service if err := service.Init(); err != nil { log.Fatal(err) } rou := httprouter.New() rou.NotFound = http.FileServer(http.Dir("html")) // register html handler service.Handle("/", rou) // run service if err := service.Run(); err != nil { log.Fatal(err) } }
# 建立工具函數文件夾 $ mkdir utils # 進入文件夾建立文件 $ cd utils # 配置文件讀取函數文件 $ sudo vim config.go # 錯誤碼文件 $ sudo vim error.go # 字符串拼接文件 $ sudo vim misc.go
配置 文件讀取文件 config.go
package utils import ( "github.com/astaxie/beego" //使用了beego框架的配置文件讀取模塊 "github.com/astaxie/beego/config" ) var ( G_server_name string //項目名稱 G_server_addr string //服務器ip地址 G_server_port string //服務器端口 G_redis_addr string //redis ip地址 G_redis_port string //redis port端口 G_redis_dbnum string //redis db 編號 G_mysql_addr string //mysql ip 地址 G_mysql_port string //mysql 端口 G_mysql_dbname string //mysql db name G_fastdfs_port string //fastdfs 端口 G_fastdfs_addr string //fastdfs ip ) func InitConfig() { //從配置文件讀取配置信息 //若是項目遷移須要進行修改 appconf, err := config.NewConfig("ini", "/home/lpgit/go/src/ihome/ihomeWeb/conf/app.conf") if err != nil { beego.Debug(err) return } G_server_name = appconf.String("appname") G_server_addr = appconf.String("httpaddr") G_server_port = appconf.String("httpport") G_redis_addr = appconf.String("redisaddr") G_redis_port = appconf.String("redisport") G_redis_dbnum = appconf.String("redisdbnum") G_mysql_addr = appconf.String("mysqladdr") G_mysql_port = appconf.String("mysqlport") G_mysql_dbname = appconf.String("mysqldbname") G_fastdfs_port = appconf.String("fastdfsport") G_fastdfs_addr = appconf.String("fastdfsaddr") return } func init() { InitConfig() }
錯誤碼文件 error.go
package utils const ( RECODE_OK = "0" RECODE_DBERR = "4001" RECODE_NODATA = "4002" RECODE_DATAEXIST = "4003" RECODE_DATAERR = "4004" RECODE_SESSIONERR = "4101" RECODE_LOGINERR = "4102" RECODE_PARAMERR = "4103" RECODE_USERERR = "4104" RECODE_ROLEERR = "4105" RECODE_PWDERR = "4106" RECODE_SMSERR = "4017" RECODE_REQERR = "4201" RECODE_IPERR = "4202" RECODE_THIRDERR = "4301" RECODE_IOERR = "4302" RECODE_SERVERERR = "4500" RECODE_UNKNOWERR = "4501" ) var recodeText = map[string]string{ RECODE_OK: "成功", RECODE_DBERR: "數據庫查詢錯誤", RECODE_NODATA: "無數據", RECODE_DATAEXIST: "數據已存在", RECODE_DATAERR: "數據錯誤", RECODE_SESSIONERR: "用戶未登陸", RECODE_LOGINERR: "用戶登陸失敗", RECODE_PARAMERR: "參數錯誤", RECODE_USERERR: "用戶不存在或未激活", RECODE_ROLEERR: "用戶身份錯誤", RECODE_PWDERR: "密碼錯誤", RECODE_REQERR: "非法請求或請求次數受限", RECODE_IPERR: "IP受限", RECODE_THIRDERR: "第三方系統錯誤", RECODE_IOERR: "文件讀寫錯誤", RECODE_SERVERERR: "內部錯誤", RECODE_UNKNOWERR: "未知錯誤", RECODE_SMSERR: "短信失敗", } func RecodeText(code string) string { str, ok := recodeText[code] if ok { return str } return recodeText[RECODE_UNKNOWERR] }
字符串拼接文件 misc.go
package utils /* 將url加上 http://IP:PROT/ 前綴 */ //http:// + 127.0.0.1 + :+ 8080 + 請求 func AddDomain2Url(url string) (domain_url string) { domain_url = "http://" + G_fastdfs_addr + ":" + G_fastdfs_port + "/" + url return domain_url }
沒有下載 mysql 驅動的先下載 mysql
$ go get -u -v github.com/go-sql-driver/mysql
$ mkdir models # 建立數據庫文件 $ sudo vim models.go
models.go
文件內容
package models import ( "github.com/astaxie/beego" // 使用了beego的orm模塊 "github.com/astaxie/beego/orm" // go語言的sql的驅動 _ "github.com/go-sql-driver/mysql" // 已經建立好的工具包 "ihome/ihomeWeb/utils" "time" ) /* 用戶 table_name = user */ type User struct { Id int `json:"user_id"` // 用戶編號 Name string `orm:"size(32)" json:"name"` // 用戶暱稱 PasswordHash string `orm:"size(128)" json:"password"` // 用戶密碼加密的 Mobile string `orm:"size(11);unique" json:"mobile"` // 手機號 RealName string `orm:"size(32)" json:"real_name"` // 真實姓名 實名認證 IdCard string `orm:"size(20)" json:"id_card"` // 身份證號 實名認證 AvatarUrl string `orm:"size(256)" json:"avatar_url"` // 用戶頭像路徑 經過 fastDFS 進行圖片存儲 Houses []*House `orm:"reverse(many)" json:"houses"` // 用戶發佈的房屋信息 一我的多套房 Orders []*OrderHouse `orm:"reverse(many)" json:"orders"` // 用戶下的訂單 一我的屢次訂單 } /* 房屋信息 table_name = house */ type House struct { Id int `json:"house_id"` // 房屋編號 User *User `orm:"rel(fk)" json:"user_id"` // 房屋主人的用戶編號 與用戶進行關聯 Area *Area `orm:"rel(fk)" json:"area_id"` // 歸屬地的區域編號 和地區表進行關聯 Title string `orm:"size(64)" json:"title"` // 房屋標題 Price int `orm:"default(0)" json:"price"` // 單價,單位:分 每次的價格要乘以100 Address string `orm:"size(512)" orm:"default('')" json:"address"` // 地址 RoomCount int `orm:"default(1)" json:"room_count"` // 房間數目 Acreage int `orm:"default(0)" json:"acreage"` // 房屋總面積 Unit string `orm:"size(32)" orm:"default('')" json:"unit"` // 房屋單元,如 幾室幾廳 Capacity int `orm:"default(1)" json:"capacity"` // 房屋容納的總人數 Beds string `orm:"size(64)" orm:"default('')" json:"beds"` // 房屋牀鋪的配置 Deposit int `orm:"default(0)" json:"deposit"` // 押金 MinDays int `orm:"default(1)" json:"min_days"` // 最少入住的天數 MaxDays int `orm:"default(0)" json:"max_days"` // 最多入住的天數 0表示不限制 OrderCount int `orm:"default(0)" json:"order_count"` // 預約完成的該房屋的訂單數 IndexImageUrl string `orm:"size(256)" orm:"default('')" json:"index_image_url"` // 房屋主圖片路徑 Facilities []*Facility `orm:"reverse(many)" json:"facilities"` // 房屋設施 與設施表進行關聯 Images []*HouseImage `orm:"reverse(many)" json:"img_urls"` // 房屋的圖片 除主要圖片以外的其餘圖片地址 Orders []*OrderHouse `orm:"reverse(many)" json:"orders"` // 房屋的訂單 與房屋表進行管理 Ctime time.Time `orm:"auto_now_add;type(datetime)" json:"ctime"` } // 首頁最高展現的房屋數量 var HomePageMaxHouses int = 5 // 房屋列表頁面每頁顯示條目數 var HouseListPageCapacity int = 2 // 處理房子信息 func (this *House) ToHouseInfo() interface{} { houseInfo := map[string]interface{}{ "house_id": this.Id, "title": this.Title, "price": this.Price, "area_name": this.Area.Name, "img_url": utils.AddDomain2Url(this.IndexImageUrl), "room_count": this.RoomCount, "order_count": this.OrderCount, "address": this.Address, "user_avatar": utils.AddDomain2Url(this.User.AvatarUrl), "ctime": this.Ctime.Format("2006-01-02 15:04:05"), } return houseInfo } // 處理 1 個房子的所有信息 func (this *House) ToOneHouseDesc() interface{} { houseDesc := map[string]interface{}{ "hid": this.Id, "user_id": this.User.Id, "user_name": this.User.Name, "user_avatar": utils.AddDomain2Url(this.User.AvatarUrl), "title": this.Title, "price": this.Price, "address": this.Address, "room_count": this.RoomCount, "acreage": this.Acreage, "unit": this.Unit, "capacity": this.Capacity, "beds": this.Beds, "deposit": this.Deposit, "min_days": this.MinDays, "max_days": this.MaxDays, } //房屋圖片 imgUrls := []string{} for _, imgUrl := range this.Images { imgUrls = append(imgUrls, utils.AddDomain2Url(imgUrl.Url)) } houseDesc["img_urls"] = imgUrls //房屋設施 facilities := []int{} for _, facility := range this.Facilities { facilities = append(facilities, facility.Id) } houseDesc["facilities"] = facilities //評論信息 comments := []interface{}{} orders := []OrderHouse{} o := orm.NewOrm() orderNum, err := o.QueryTable("order_house").Filter("house__id", this.Id).Filter("status", OrderStatusComplete).OrderBy("-ctime").Limit(10).All(&orders) if err != nil { beego.Error("select orders comments error, err =", err, "house id = ", this.Id) } for i := 0; i < int(orderNum); i++ { o.LoadRelated(&orders[i], "User") var username string if orders[i].User.Name == "" { username = "匿名用戶" } else { username = orders[i].User.Name } comment := map[string]string{ "comment": orders[i].Comment, "user_name": username, "ctime": orders[i].Ctime.Format("2006-01-02 15:04:05"), } comments = append(comments, comment) } houseDesc["comments"] = comments return houseDesc } /* 區域信息 table_name = area */ //區域信息是須要咱們手動添加到數據庫中的 type Area struct { Id int `json:"aid"` // 區域編號 1 2 Name string `orm:"size(32)" json:"aname"` // 區域名字 昌平 海淀 Houses []*House `orm:"reverse(many)" json:"houses"` // 區域全部的房屋 與房屋表進行關聯 } /* 設施信息 table_name = "facility"*/ // 設施信息 須要咱們提早手動添加的 type Facility struct { Id int `json:"fid"` // 設施編號 Name string `orm:"size(32)"` // 設施名字 Houses []*House `orm:"rel(m2m)"` // 都有哪些房屋有此設施 與房屋表進行關聯的 } /* 房屋圖片 table_name = "house_image"*/ type HouseImage struct { Id int `json:"house_image_id"` // 圖片 id Url string `orm:"size(256)" json:"url"` // 圖片 url 存放咱們房屋的圖片 House *House `orm:"rel(fk)" json:"house_id"` // 圖片所屬房屋編號 } const ( OrderStatusWaitAccept = "WAIT_ACCEPT" //待接單 OrderStatusWaitPayment = "WAIT_PAYMENT" //待支付 OrderStatusPaid = "PAID" //已支付 OrderStatusWaitComment = "WAIT_COMMENT" //待評價 OrderStatusComplete = "COMPLETE" //已完成 OrderStatusCanceled = "CONCELED" //已取消 OrderStatusRejected = "REJECTED" //已拒單 ) /* 訂單 table_name = order */ type OrderHouse struct { Id int `json:"order_id"` //訂單編號 User *User `orm:"rel(fk)" json:"user_id"` //下單的用戶編號 //與用戶表進行關聯 House *House `orm:"rel(fk)" json:"house_id"` //預約的房間編號 //與房屋信息進行關聯 BeginDate time.Time `orm:"type(datetime)"` //預約的起始時間 EndDate time.Time `orm:"type(datetime)"` //預約的結束時間 Days int //預約總天數 HousePrice int //房屋的單價 Amount int //訂單總金額 Status string `orm:"default(WAIT_ACCEPT)"` //訂單狀態 Comment string `orm:"size(512)"` //訂單評論 Ctime time.Time `orm:"auto_now;type(datetime)" json:"ctime"` //每次更新此表,都會更新這個字段 Credit bool //表示我的徵信狀況 true表示良好 } // 處理訂單信息 func (this *OrderHouse) ToOrderInfo() interface{} { orderInfo := map[string]interface{}{ "order_id": this.Id, "title": this.House.Title, "img_url": utils.AddDomain2Url(this.House.IndexImageUrl), "start_date": this.BeginDate.Format("2006-01-02 15:04:05"), "end_date": this.EndDate.Format("2006-01-02 15:04:05"), "ctime": this.Ctime.Format("2006-01-02 15:04:05"), "days": this.Days, "amount": this.Amount, "status": this.Status, "comment": this.Comment, "credit": this.Credit, } return orderInfo } // 數據庫的初始化 func init() { //調用什麼驅動 orm.RegisterDriver("mysql", orm.DRMySQL) // set default database // 鏈接數據 ( 默認參數 ,mysql數據庫 ,"數據庫的用戶名 :數據庫密碼@tcp("+數據庫地址+":"+數據庫端口+")/庫名?格式",默認參數) orm.RegisterDataBase("default", "mysql", "root:lpg123456@tcp("+utils.G_mysql_addr+":"+utils.G_mysql_port+")/ihome?charset=utf8", 30) // 註冊 model 建表 orm.RegisterModel(new(User), new(House), new(Area), new(Facility), new(HouseImage), new(OrderHouse)) // create table //第一個是別名 // 第二個是是否強制替換模塊 若是表變動就將false 換成true 以後再換回來表就便更好來了 //第三個參數是若是沒有則同步或建立 orm.RunSyncdb("default", false, true) }
# 建立 conf 文件夾用來存放配置文件 $ mkdir conf # 建立data.sql文件 $ sudo vim data.sql
datat.sql
文件內容
INSERT INTO `area`(`name`) VALUES ('東城區'),('西城區'),('朝陽區'),('海淀區'),('昌平區'),('豐臺區'),('房山區'),('通州區'),('順義區'),('大興區'),('懷柔區'),('平谷區'),('密雲區'),('延慶區'),('石景山區'); INSERT INTO `facility`(`name`) VALUES('無線網絡'),('熱水淋浴'),('空調'),('暖氣'),('容許吸菸'),('飲水設備'),('牙具'),('香皂'),('拖鞋'),('手紙'),('毛巾'),('沐浴露、洗髮露'),('冰箱'),('洗衣機'),('電梯'),('容許作飯'),('容許帶寵物'),('容許聚會'),('門禁系統'),('停車位'),('有線網絡'),('電視'),('浴缸'),('吃雞'),('打檯球');
main.go
內容import ( _ "ihome/ihomeWeb/models" )
mysql
進行數據導入# 登陸mysql $ mysql -uroot -p # 輸入root密碼 Mysql> use ihome; # 數據的導入 mysql> source ./conf/data.sql; # 數據檢查 mysql> select * from area; mysql> select * from facility;
app.conf
文件# 應用名稱 appname = ihome # 地址 httpaddr = 127.0.0.1 # 端口 httpport = 8080 # 數據庫地址 mysqladdr = 127.0.0.1 # 數據庫端口 mysqlport = 3306
html 文件下載地址:https://cloud.189.cn/t/IzYbIbQVbEJn (訪問碼: 2owm)
go run main.go
打開瀏覽器,輸入:127.0.0.1:8080
,就能夠看到效果啦。
接下來, 我就帶領你們一步一步完成每一個服務。
歡迎訪問個人我的網站:
李培冠博客:lpgit.com