显示好友列表和群

一、如何添加/显示好友 添加/显示群

可以具体成如下的几个接口

  1. /contact/addfriend 自动添加好友,参数userid,dstid
  2. //
  3. 用户10000添加好友10086,往contact表中添加俩条记录
  4. //一条ownerid =10000,dstobj=10086
  5. //一条ownerid =10086,dstobj=10000
  6. /contact/loadfriend 显示全部好友,参数userid
  7. /contact/createcommunity 建群,头像pic,名称name,备注memo,创建者userid
  8. /contact/loadcommunity 显示全部群 参数userid
  9. //加群逻辑特殊一点
  10. /contact/joincommunity 加群,参数userid,dstid

二、创建模型(实体)

model/contact.go

  1. package model
  2. import "time"
  3. // 好友和群都存在这个表里
  4. // 可根据具体业务做拆分
  5. type Contact struct {
  6. Id int64 `xorm:"pk autoincr bigint(20)" form:"id" json:"id"`
  7. // 谁的10000 添加的人
  8. Ownerid int64 `xorm:"bigint(20)" form:"ownerid" json:"ownerid"`
  9. // 对端10001 被添加的人
  10. Dstobj int64 `xorm:"bigint(20)" form:"dstobj" json:"dstobj"`
  11. // 是下面定义的常量 用户加用户是0x01 用户加群0x02
  12. Cate int `xorm:"int(11)" form:"cate" json:"cate"`
  13. Memo string `xorm:"varchar(120)" form:"memo" json:"memo"` // 什么角色
  14. Createat time.Time `xorm:"datetime" form:"createat" json:"createat"` // 什么角色
  15. }
  16. const (
  17. CONCAT_CATE_USER = 0x01 //用户
  18. CONCAT_CATE_COMUNITY = 0x02 //群组
  19. )

model/community.go 群聊模型

  1. package model
  2. import "time"
  3. type Community struct {
  4. Id int64 `xorm:"pk autoincr bigint(20)" form:"id" json:"id"`
  5. //名称
  6. Name string `xorm:"varchar(30)" form:"name" json:"name"`
  7. //群主ID
  8. Ownerid int64 `xorm:"bigint(20)" form:"ownerid" json:"ownerid"` // 什么角色
  9. //群logo
  10. Icon string `xorm:"varchar(250)" form:"icon" json:"icon"`
  11. //como
  12. Cate int `xorm:"int(11)" form:"cate" json:"cate"` // 什么角色
  13. //描述
  14. Memo string `xorm:"varchar(120)" form:"memo" json:"memo"` // 什么角色
  15. //
  16. Createat time.Time `xorm:"datetime" form:"createat" json:"createat"` // 什么角色
  17. }
  18. const (
  19. COMMUNITY_CATE_COM = 0x01
  20. )

在service/init.go中自动同步模型的结构体和数居库的表结构生成映射的关系 19、显示好友列表和群 - 图1

三、创建控制器controller

  1. func Addfriend(w http.ResponseWriter, req *http.Request) {
  2. //request.ParseForm()
  3. //mobile := request.PostForm.Get("mobile")
  4. //passwd := request.PostForm.Get("passwd")
  5. //str->int
  6. //
  7. var arg args.ContactArg
  8. //对象绑定
  9. util.Bind(req,&arg)
  10. //
  11. err := contactService.AddFriend(arg.Userid,arg.Dstid)
  12. if err!=nil{
  13. util.RespFail(w,err.Error())
  14. }else{
  15. util.RespOk(w,msgs)
  16. }
  17. }

封装第9行代码的util.Bind方法 19、显示好友列表和群 - 图2

  1. package util
  2. import (
  3. "net/http"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "reflect"
  9. "strconv"
  10. "strings"
  11. "time"
  12. )
  13. func Bind(req *http.Request, obj interface{}) error {
  14. contentType := req.Header.Get("Content-Type")
  15. //如果是简单的json
  16. if strings.Contains(strings.ToLower(contentType), "application/json") {
  17. return BindJson(req, obj)
  18. }
  19. if strings.Contains(strings.ToLower(contentType), "application/x-www-form-urlencoded") {
  20. return BindForm(req, obj)
  21. }
  22. return errors.New("当前方法暂不支持")
  23. }
  24. func BindJson(req *http.Request, obj interface{}) error {
  25. s, err := ioutil.ReadAll(req.Body) //把 body 内容读入字符串
  26. if err != nil {
  27. return err
  28. }
  29. err = json.Unmarshal(s, obj)
  30. return err
  31. }
  32. func BindForm(req *http.Request, ptr interface{}) error {
  33. req.ParseForm()
  34. fmt.Println(req.Form.Encode())
  35. err := mapForm(ptr, req.Form)
  36. return err
  37. }
  38. // 自动绑定方法
  39. // 借鉴了gin
  40. // 改良了时间绑定,
  41. func mapForm(ptr interface{}, form map[string][]string) error {
  42. typ := reflect.TypeOf(ptr).Elem()
  43. val := reflect.ValueOf(ptr).Elem()
  44. for i := 0; i < typ.NumField(); i++ {
  45. typeField := typ.Field(i)
  46. structField := val.Field(i)
  47. if !structField.CanSet() {
  48. continue
  49. }
  50. structFieldKind := structField.Kind()
  51. inputFieldName := typeField.Tag.Get("form")
  52. if inputFieldName == "" {
  53. inputFieldName = typeField.Name
  54. // if "form" tag is nil, we inspect if the field is a struct.
  55. // this would not make sense for JSON parsing but it does for a form
  56. // since data is flatten
  57. if structFieldKind == reflect.Struct {
  58. err := mapForm(structField.Addr().Interface(), form)
  59. if err != nil {
  60. return err
  61. }
  62. continue
  63. }
  64. }
  65. inputValue, exists := form[inputFieldName]
  66. if !exists {
  67. continue
  68. }
  69. numElems := len(inputValue)
  70. if structFieldKind == reflect.Slice && numElems > 0 {
  71. sliceOf := structField.Type().Elem().Kind()
  72. slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
  73. for i := 0; i < numElems; i++ {
  74. if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
  75. return err
  76. }
  77. }
  78. val.Field(i).Set(slice)
  79. } else {
  80. if _, isTime := structField.Interface().(time.Time); isTime {
  81. if err := setTimeField(inputValue[0], typeField, structField); err != nil {
  82. return err
  83. }
  84. continue
  85. }
  86. if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
  87. return err
  88. }
  89. }
  90. }
  91. return nil
  92. }
  93. func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
  94. switch valueKind {
  95. case reflect.Int:
  96. return setIntField(val, 0, structField)
  97. case reflect.Int8:
  98. return setIntField(val, 8, structField)
  99. case reflect.Int16:
  100. return setIntField(val, 16, structField)
  101. case reflect.Int32:
  102. return setIntField(val, 32, structField)
  103. case reflect.Int64:
  104. return setIntField(val, 64, structField)
  105. case reflect.Uint:
  106. return setUintField(val, 0, structField)
  107. case reflect.Uint8:
  108. return setUintField(val, 8, structField)
  109. case reflect.Uint16:
  110. return setUintField(val, 16, structField)
  111. case reflect.Uint32:
  112. return setUintField(val, 32, structField)
  113. case reflect.Uint64:
  114. return setUintField(val, 64, structField)
  115. case reflect.Bool:
  116. return setBoolField(val, structField)
  117. case reflect.Float32:
  118. return setFloatField(val, 32, structField)
  119. case reflect.Float64:
  120. return setFloatField(val, 64, structField)
  121. case reflect.String:
  122. structField.SetString(val)
  123. default:
  124. return errors.New("Unknown type")
  125. }
  126. return nil
  127. }
  128. func setIntField(val string, bitSize int, field reflect.Value) error {
  129. if val == "" {
  130. val = "0"
  131. }
  132. intVal, err := strconv.ParseInt(val, 10, bitSize)
  133. if err == nil {
  134. field.SetInt(intVal)
  135. }
  136. return err
  137. }
  138. func setUintField(val string, bitSize int, field reflect.Value) error {
  139. if val == "" {
  140. val = "0"
  141. }
  142. uintVal, err := strconv.ParseUint(val, 10, bitSize)
  143. if err == nil {
  144. field.SetUint(uintVal)
  145. }
  146. return err
  147. }
  148. func setBoolField(val string, field reflect.Value) error {
  149. if val == "" {
  150. val = "false"
  151. }
  152. boolVal, err := strconv.ParseBool(val)
  153. if err == nil {
  154. field.SetBool(boolVal)
  155. }
  156. return nil
  157. }
  158. func setFloatField(val string, bitSize int, field reflect.Value) error {
  159. if val == "" {
  160. val = "0.0"
  161. }
  162. floatVal, err := strconv.ParseFloat(val, bitSize)
  163. if err == nil {
  164. field.SetFloat(floatVal)
  165. }
  166. return err
  167. }
  168. func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
  169. timeFormat := structField.Tag.Get("time_format")
  170. //2018-01-02 01:02:03
  171. if timeFormat == "" {
  172. timeFormat = "2006-01-02 15:04:05"
  173. val = strings.Replace(val, "/", "-", 0)
  174. num := len(strings.Split(val, " "))
  175. if num == 1 {
  176. val = val + " 00:00:00"
  177. } else {
  178. //2018-01-02 00
  179. num = len(strings.Split(val, ":"))
  180. if num == 1 {
  181. val = val + ":00:00"
  182. } else if num == 2 {
  183. val = val + ":00"
  184. }
  185. }
  186. }
  187. if val == "" {
  188. value.Set(reflect.ValueOf(time.Time{}))
  189. return nil
  190. }
  191. l := time.Local
  192. if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
  193. l = time.UTC
  194. }
  195. if locTag := structField.Tag.Get("time_location"); locTag != "" {
  196. loc, err := time.LoadLocation(locTag)
  197. if err != nil {
  198. return err
  199. }
  200. l = loc
  201. }
  202. t, err := time.ParseInLocation(timeFormat, val, l)
  203. if err != nil {
  204. return err
  205. }
  206. value.Set(reflect.ValueOf(t))
  207. return nil
  208. }
  209. // Don't pass in pointers to bind to. Can lead to bugs. See:
  210. // https://github.com/codegangsta/martini-contrib/issues/40
  211. // https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
  212. func ensureNotPointer(obj interface{}) {
  213. if reflect.TypeOf(obj).Kind() == reflect.Ptr {
  214. panic("Pointers are not accepted as binding models")
  215. }
  216. }

四、配置路由

http.HandleFunc(“/contact/addfriend”, controller.Addfriend) 19、显示好友列表和群 - 图3

五、配置service

service下contact.go自动添加好友业务逻辑 19、显示好友列表和群 - 图4

  1. package service
  2. import (
  3. "errors"
  4. "hello/model"
  5. "time"
  6. )
  7. type ContactService struct {
  8. }
  9. //自动添加好友
  10. func (service *ContactService) AddFriend(
  11. userid, //用户id 10086,
  12. dstid int64) error {
  13. //如果加自己
  14. if userid == dstid {
  15. return errors.New("不能添加自己为好友啊")
  16. }
  17. //判断是否已经加了好友
  18. tmp := model.Contact{}
  19. //查询是否已经是好友
  20. // 条件的链式操作
  21. DbEngin.Where("ownerid = ?", userid).
  22. And("dstid = ?", dstid).
  23. And("cate = ?", model.CONCAT_CATE_USER).
  24. Get(&tmp)
  25. //获得1条记录
  26. //count()
  27. //如果存在记录说明已经是好友了不加
  28. if tmp.Id > 0 {
  29. return errors.New("该用户已经被添加过啦")
  30. }
  31. //事务,
  32. session := DbEngin.NewSession()
  33. session.Begin()
  34. //插自己的
  35. _, e2 := session.InsertOne(model.Contact{
  36. Ownerid: userid,
  37. Dstobj: dstid,
  38. Cate: model.CONCAT_CATE_USER,
  39. Createat: time.Now(),
  40. })
  41. //插对方的
  42. _, e3 := session.InsertOne(model.Contact{
  43. Ownerid: dstid,
  44. Dstobj: userid,
  45. Cate: model.CONCAT_CATE_USER,
  46. Createat: time.Now(),
  47. })
  48. //没有错误
  49. if e2 == nil && e3 == nil {
  50. //提交
  51. session.Commit()
  52. return nil
  53. } else {
  54. //回滚
  55. session.Rollback()
  56. if e2 != nil {
  57. return e2
  58. } else {
  59. return e3
  60. }
  61. }
  62. }

实现controller层下contact.go的Addfriend方法

  1. package controller
  2. import (
  3. "hello/args"
  4. "hello/service"
  5. "hello/util"
  6. "net/http"
  7. )
  8. var contactService service.ContactService
  9. func Addfriend(w http.ResponseWriter, req *http.Request) {
  10. //定义一个参数结构体
  11. /*request.ParseForm()
  12. mobile := request.PostForm.Get("mobile")
  13. passwd := request.PostForm.Get("passwd")
  14. */
  15. var arg args.ContactArg
  16. util.Bind(req, &arg)
  17. //调用service
  18. err := contactService.AddFriend(arg.Userid, arg.Dstid)
  19. //
  20. if err != nil {
  21. util.RespFail(w, err.Error())
  22. } else {
  23. util.RespOk(w, nil, "好友添加成功")
  24. }
  25. }

会发现调用的一些包没有,则进行扩展 19、显示好友列表和群 - 图5

args目录下的contact.go 19、显示好友列表和群 - 图6

  1. package args
  2. type ContactArg struct {
  3. PageArg
  4. Userid int64 `json:"userid" form:"userid"`
  5. Dstid int64 `json:"dstid" form:"dstid"`
  6. }

args目录下的pagearg.go

  1. package args
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. type PageArg struct {
  7. //从哪页开始
  8. Pagefrom int `json:"pagefrom" form:"pagefrom"`
  9. //每页大小
  10. Pagesize int `json:"pagesize" form:"pagesize"`
  11. //关键词
  12. Kword string `json:"kword" form:"kword"`
  13. //asc:“id” id asc
  14. Asc string `json:"asc" form:"asc"`
  15. Desc string `json:"desc" form:"desc"`
  16. //
  17. Name string `json:"name" form:"name"`
  18. //
  19. Userid int64 `json:"userid" form:"userid"`
  20. //dstid
  21. Dstid int64 `json:"dstid" form:"dstid"`
  22. //时间点1
  23. Datefrom time.Time `json:"datafrom" form:"datafrom"`
  24. //时间点2
  25. Dateto time.Time `json:"dateto" form:"dateto"`
  26. //
  27. Total int64 `json:"total" form:"total"`
  28. }
  29. func (p*PageArg) GetPageSize() int{
  30. if p.Pagesize==0{
  31. return 100
  32. }else{
  33. return p.Pagesize
  34. }
  35. }
  36. func (p*PageArg) GetPageFrom() int{
  37. if p.Pagefrom<0{
  38. return 0
  39. }else{
  40. return p.Pagefrom
  41. }
  42. }
  43. func (p*PageArg) GetOrderBy() string{
  44. if len(p.Asc)>0{
  45. return fmt.Sprintf(" %s asc",p.Asc)
  46. } else if len(p.Desc)>0{
  47. return fmt.Sprintf(" %s desc",p.Desc)
  48. }else{
  49. return ""
  50. }
  51. }

六、前端js

  1. addfriend:function(){
  2. //弹窗提示用户输入
  3. // mui.prompt()
  4. }
  5. _addfriend:function(){
  6. //网络请求
  7. }

19、显示好友列表和群 - 图7

七、测试

一定要进行更换view/chat的代码及完善controller下/contact.go代码完善了好友列表等方法,main.go也完善了路由

自己添加自己不成功

19、显示好友列表和群 - 图8

19、显示好友列表和群 - 图9

  1. /contact/loadfriend 显示全部好友,参数userid
  2. /contact/createcommunity 建群,头像pic,名称name,备注memo,创建者userid
  3. /contact/loadcommunity 显示全部群 参数userid
  4. //加群逻辑特殊一点
  5. /contact/joincommunity 加群,参数userid,dstid

这5个接口自行编写,或者参下面的git仓库地址v1.2标签

封装了分页返回数据util/resp.go 19、显示好友列表和群 - 图10

后续的接口代码放到了gitee仓库中:显示好友列表和群