显示好友列表和群
一、如何添加/显示好友 添加/显示群
可以具体成如下的几个接口
/contact/addfriend 自动添加好友,参数userid,dstid
//
用户10000添加好友10086,往contact表中添加俩条记录
//一条ownerid =10000,dstobj=10086
//一条ownerid =10086,dstobj=10000
/contact/loadfriend 显示全部好友,参数userid
/contact/createcommunity 建群,头像pic,名称name,备注memo,创建者userid
/contact/loadcommunity 显示全部群 参数userid
//加群逻辑特殊一点
/contact/joincommunity 加群,参数userid,dstid
二、创建模型(实体)
model/contact.go
package model
import "time"
// 好友和群都存在这个表里
// 可根据具体业务做拆分
type Contact struct {
Id int64 `xorm:"pk autoincr bigint(20)" form:"id" json:"id"`
// 谁的10000 添加的人
Ownerid int64 `xorm:"bigint(20)" form:"ownerid" json:"ownerid"`
// 对端10001 被添加的人
Dstobj int64 `xorm:"bigint(20)" form:"dstobj" json:"dstobj"`
// 是下面定义的常量 用户加用户是0x01 用户加群0x02
Cate int `xorm:"int(11)" form:"cate" json:"cate"`
Memo string `xorm:"varchar(120)" form:"memo" json:"memo"` // 什么角色
Createat time.Time `xorm:"datetime" form:"createat" json:"createat"` // 什么角色
}
const (
CONCAT_CATE_USER = 0x01 //用户
CONCAT_CATE_COMUNITY = 0x02 //群组
)
model/community.go 群聊模型
package model
import "time"
type Community struct {
Id int64 `xorm:"pk autoincr bigint(20)" form:"id" json:"id"`
//名称
Name string `xorm:"varchar(30)" form:"name" json:"name"`
//群主ID
Ownerid int64 `xorm:"bigint(20)" form:"ownerid" json:"ownerid"` // 什么角色
//群logo
Icon string `xorm:"varchar(250)" form:"icon" json:"icon"`
//como
Cate int `xorm:"int(11)" form:"cate" json:"cate"` // 什么角色
//描述
Memo string `xorm:"varchar(120)" form:"memo" json:"memo"` // 什么角色
//
Createat time.Time `xorm:"datetime" form:"createat" json:"createat"` // 什么角色
}
const (
COMMUNITY_CATE_COM = 0x01
)
在service/init.go中自动同步模型的结构体和数居库的表结构生成映射的关系
三、创建控制器controller
func Addfriend(w http.ResponseWriter, req *http.Request) {
//request.ParseForm()
//mobile := request.PostForm.Get("mobile")
//passwd := request.PostForm.Get("passwd")
//str->int
//
var arg args.ContactArg
//对象绑定
util.Bind(req,&arg)
//
err := contactService.AddFriend(arg.Userid,arg.Dstid)
if err!=nil{
util.RespFail(w,err.Error())
}else{
util.RespOk(w,msgs)
}
}
封装第9行代码的util.Bind方法
package util
import (
"net/http"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"reflect"
"strconv"
"strings"
"time"
)
func Bind(req *http.Request, obj interface{}) error {
contentType := req.Header.Get("Content-Type")
//如果是简单的json
if strings.Contains(strings.ToLower(contentType), "application/json") {
return BindJson(req, obj)
}
if strings.Contains(strings.ToLower(contentType), "application/x-www-form-urlencoded") {
return BindForm(req, obj)
}
return errors.New("当前方法暂不支持")
}
func BindJson(req *http.Request, obj interface{}) error {
s, err := ioutil.ReadAll(req.Body) //把 body 内容读入字符串
if err != nil {
return err
}
err = json.Unmarshal(s, obj)
return err
}
func BindForm(req *http.Request, ptr interface{}) error {
req.ParseForm()
fmt.Println(req.Form.Encode())
err := mapForm(ptr, req.Form)
return err
}
// 自动绑定方法
// 借鉴了gin
// 改良了时间绑定,
func mapForm(ptr interface{}, form map[string][]string) error {
typ := reflect.TypeOf(ptr).Elem()
val := reflect.ValueOf(ptr).Elem()
for i := 0; i < typ.NumField(); i++ {
typeField := typ.Field(i)
structField := val.Field(i)
if !structField.CanSet() {
continue
}
structFieldKind := structField.Kind()
inputFieldName := typeField.Tag.Get("form")
if inputFieldName == "" {
inputFieldName = typeField.Name
// if "form" tag is nil, we inspect if the field is a struct.
// this would not make sense for JSON parsing but it does for a form
// since data is flatten
if structFieldKind == reflect.Struct {
err := mapForm(structField.Addr().Interface(), form)
if err != nil {
return err
}
continue
}
}
inputValue, exists := form[inputFieldName]
if !exists {
continue
}
numElems := len(inputValue)
if structFieldKind == reflect.Slice && numElems > 0 {
sliceOf := structField.Type().Elem().Kind()
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
for i := 0; i < numElems; i++ {
if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
return err
}
}
val.Field(i).Set(slice)
} else {
if _, isTime := structField.Interface().(time.Time); isTime {
if err := setTimeField(inputValue[0], typeField, structField); err != nil {
return err
}
continue
}
if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
return err
}
}
}
return nil
}
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
switch valueKind {
case reflect.Int:
return setIntField(val, 0, structField)
case reflect.Int8:
return setIntField(val, 8, structField)
case reflect.Int16:
return setIntField(val, 16, structField)
case reflect.Int32:
return setIntField(val, 32, structField)
case reflect.Int64:
return setIntField(val, 64, structField)
case reflect.Uint:
return setUintField(val, 0, structField)
case reflect.Uint8:
return setUintField(val, 8, structField)
case reflect.Uint16:
return setUintField(val, 16, structField)
case reflect.Uint32:
return setUintField(val, 32, structField)
case reflect.Uint64:
return setUintField(val, 64, structField)
case reflect.Bool:
return setBoolField(val, structField)
case reflect.Float32:
return setFloatField(val, 32, structField)
case reflect.Float64:
return setFloatField(val, 64, structField)
case reflect.String:
structField.SetString(val)
default:
return errors.New("Unknown type")
}
return nil
}
func setIntField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0"
}
intVal, err := strconv.ParseInt(val, 10, bitSize)
if err == nil {
field.SetInt(intVal)
}
return err
}
func setUintField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0"
}
uintVal, err := strconv.ParseUint(val, 10, bitSize)
if err == nil {
field.SetUint(uintVal)
}
return err
}
func setBoolField(val string, field reflect.Value) error {
if val == "" {
val = "false"
}
boolVal, err := strconv.ParseBool(val)
if err == nil {
field.SetBool(boolVal)
}
return nil
}
func setFloatField(val string, bitSize int, field reflect.Value) error {
if val == "" {
val = "0.0"
}
floatVal, err := strconv.ParseFloat(val, bitSize)
if err == nil {
field.SetFloat(floatVal)
}
return err
}
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
timeFormat := structField.Tag.Get("time_format")
//2018-01-02 01:02:03
if timeFormat == "" {
timeFormat = "2006-01-02 15:04:05"
val = strings.Replace(val, "/", "-", 0)
num := len(strings.Split(val, " "))
if num == 1 {
val = val + " 00:00:00"
} else {
//2018-01-02 00
num = len(strings.Split(val, ":"))
if num == 1 {
val = val + ":00:00"
} else if num == 2 {
val = val + ":00"
}
}
}
if val == "" {
value.Set(reflect.ValueOf(time.Time{}))
return nil
}
l := time.Local
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
l = time.UTC
}
if locTag := structField.Tag.Get("time_location"); locTag != "" {
loc, err := time.LoadLocation(locTag)
if err != nil {
return err
}
l = loc
}
t, err := time.ParseInLocation(timeFormat, val, l)
if err != nil {
return err
}
value.Set(reflect.ValueOf(t))
return nil
}
// Don't pass in pointers to bind to. Can lead to bugs. See:
// https://github.com/codegangsta/martini-contrib/issues/40
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
func ensureNotPointer(obj interface{}) {
if reflect.TypeOf(obj).Kind() == reflect.Ptr {
panic("Pointers are not accepted as binding models")
}
}
四、配置路由
http.HandleFunc(“/contact/addfriend”, controller.Addfriend)
五、配置service
service下contact.go自动添加好友业务逻辑
package service
import (
"errors"
"hello/model"
"time"
)
type ContactService struct {
}
//自动添加好友
func (service *ContactService) AddFriend(
userid, //用户id 10086,
dstid int64) error {
//如果加自己
if userid == dstid {
return errors.New("不能添加自己为好友啊")
}
//判断是否已经加了好友
tmp := model.Contact{}
//查询是否已经是好友
// 条件的链式操作
DbEngin.Where("ownerid = ?", userid).
And("dstid = ?", dstid).
And("cate = ?", model.CONCAT_CATE_USER).
Get(&tmp)
//获得1条记录
//count()
//如果存在记录说明已经是好友了不加
if tmp.Id > 0 {
return errors.New("该用户已经被添加过啦")
}
//事务,
session := DbEngin.NewSession()
session.Begin()
//插自己的
_, e2 := session.InsertOne(model.Contact{
Ownerid: userid,
Dstobj: dstid,
Cate: model.CONCAT_CATE_USER,
Createat: time.Now(),
})
//插对方的
_, e3 := session.InsertOne(model.Contact{
Ownerid: dstid,
Dstobj: userid,
Cate: model.CONCAT_CATE_USER,
Createat: time.Now(),
})
//没有错误
if e2 == nil && e3 == nil {
//提交
session.Commit()
return nil
} else {
//回滚
session.Rollback()
if e2 != nil {
return e2
} else {
return e3
}
}
}
实现controller层下contact.go的Addfriend方法
package controller
import (
"hello/args"
"hello/service"
"hello/util"
"net/http"
)
var contactService service.ContactService
func Addfriend(w http.ResponseWriter, req *http.Request) {
//定义一个参数结构体
/*request.ParseForm()
mobile := request.PostForm.Get("mobile")
passwd := request.PostForm.Get("passwd")
*/
var arg args.ContactArg
util.Bind(req, &arg)
//调用service
err := contactService.AddFriend(arg.Userid, arg.Dstid)
//
if err != nil {
util.RespFail(w, err.Error())
} else {
util.RespOk(w, nil, "好友添加成功")
}
}
会发现调用的一些包没有,则进行扩展
args目录下的contact.go
package args
type ContactArg struct {
PageArg
Userid int64 `json:"userid" form:"userid"`
Dstid int64 `json:"dstid" form:"dstid"`
}
args目录下的pagearg.go
package args
import (
"fmt"
"time"
)
type PageArg struct {
//从哪页开始
Pagefrom int `json:"pagefrom" form:"pagefrom"`
//每页大小
Pagesize int `json:"pagesize" form:"pagesize"`
//关键词
Kword string `json:"kword" form:"kword"`
//asc:“id” id asc
Asc string `json:"asc" form:"asc"`
Desc string `json:"desc" form:"desc"`
//
Name string `json:"name" form:"name"`
//
Userid int64 `json:"userid" form:"userid"`
//dstid
Dstid int64 `json:"dstid" form:"dstid"`
//时间点1
Datefrom time.Time `json:"datafrom" form:"datafrom"`
//时间点2
Dateto time.Time `json:"dateto" form:"dateto"`
//
Total int64 `json:"total" form:"total"`
}
func (p*PageArg) GetPageSize() int{
if p.Pagesize==0{
return 100
}else{
return p.Pagesize
}
}
func (p*PageArg) GetPageFrom() int{
if p.Pagefrom<0{
return 0
}else{
return p.Pagefrom
}
}
func (p*PageArg) GetOrderBy() string{
if len(p.Asc)>0{
return fmt.Sprintf(" %s asc",p.Asc)
} else if len(p.Desc)>0{
return fmt.Sprintf(" %s desc",p.Desc)
}else{
return ""
}
}
六、前端js
addfriend:function(){
//弹窗提示用户输入
// mui.prompt()
}
_addfriend:function(){
//网络请求
}
七、测试
一定要进行更换view/chat的代码及完善controller下/contact.go代码完善了好友列表等方法,main.go也完善了路由
自己添加自己不成功
- /contact/loadfriend 显示全部好友,参数userid
- /contact/createcommunity 建群,头像pic,名称name,备注memo,创建者userid
- /contact/loadcommunity 显示全部群 参数userid
- //加群逻辑特殊一点
- /contact/joincommunity 加群,参数userid,dstid
这5个接口自行编写,或者参下面的git仓库地址v1.2标签
封装了分页返回数据util/resp.go
后续的接口代码放到了gitee仓库中:显示好友列表和群