一、单一职责(一个服务只作一件事)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