jiaojiao7 преди 3 години
родител
ревизия
d05c27f0ce

+ 18 - 34
api/internal/logic/multiplesavemsglogic.go

@@ -1,16 +1,13 @@
 package logic
 
 import (
+	"app.yhyue.com/moapp/MessageCenter/api/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/api/internal/types"
 	"app.yhyue.com/moapp/MessageCenter/rpc/messageclient"
 	"app.yhyue.com/moapp/MessageCenter/util"
 	"context"
-	"log"
-	"strconv"
-
-	"app.yhyue.com/moapp/MessageCenter/api/internal/svc"
-	"app.yhyue.com/moapp/MessageCenter/api/internal/types"
-
 	"github.com/tal-tech/go-zero/core/logx"
+	"log"
 )
 
 type MultipleSaveMsgLogic struct {
@@ -39,40 +36,27 @@ func (l *MultipleSaveMsgLogic) MultipleSaveMsg(req types.MultipleSaveMsgReq) (*t
 	//		ErrCount: 0,
 	//	}, nil
 	//}
-
 	errCount := 0
 	lsi := l.svcCtx.MessageCenter
-	var userIdList []map[string]interface{}
-	for _, val := range req.SaveData {
-		msgType_, err := strconv.Atoi(util.ObjToString(val["msgType"]))
-		msgType := int64(msgType_)
-		var CiteId int64
-		if val["citeId"] != nil {
-			CiteId_, err := strconv.Atoi(util.ObjToString(val["citeId"]))
-			CiteId = int64(CiteId_)
-			log.Println(err)
-		}
-
-		_, err = lsi.SendUserMsg(l.ctx, &messageclient.SendMsgRequest{
-			Appid:         util.ObjToString(val["appid"]),
-			ReceiveUserId: util.ObjToString(val["receiveUserId"]),
-			ReceiveName:   util.ObjToString(val["receiveName"]),
-			SendUserId:    util.ObjToString(val["sendUserId"]),
-			SendName:      util.ObjToString(val["sendName"]),
-			Title:         util.ObjToString(val["title"]),
-			Content:       util.ObjToString(val["content"]),
-			MsgType:       msgType,
-			Link:          util.ObjToString(val["link"]),
-			CiteId:        CiteId,
-		})
-		if err != nil {
-			errCount++
-		}
+	msgInfo := req.MsgInfo
+	_, err := lsi.MultipleSaveMsg(l.ctx, &messageclient.MultipleSaveMsgReq{
+		Appid:      util.ObjToString(msgInfo["appid"]),
+		SendUserId: util.ObjToString(msgInfo["sendUserId"]),
+		SendName:   util.ObjToString(msgInfo["sendName"]),
+		Title:      util.ObjToString(msgInfo["title"]),
+		Content:    util.ObjToString(msgInfo["content"]),
+		MsgType:    int64(util.IntAll(msgInfo["msgType"])),
+		Link:       util.ObjToString(msgInfo["link"]),
+		CiteId:     0,
+		UserIds:    req.UserIds,
+		UserNames:  req.UserNames,
+	})
+	if err != nil {
+		errCount++
 	}
 	return &types.MultipleSaveMsgResp{
 		Code:     1,
 		Message:  "保存成功",
 		ErrCount: int64(errCount),
-		Data:     userIdList,
 	}, nil
 }

+ 6 - 5
api/internal/types/types.go

@@ -127,12 +127,13 @@ type SendMsgResp struct {
 }
 
 type MultipleSaveMsgReq struct {
-	SaveData []map[string]interface{} `json:"saveData"`
+	MsgInfo   map[string]interface{} `json:"msgInfo"`
+	UserIds   string                 `json:"userIds"`
+	UserNames string                 `json:"userNames"`
 }
 
 type MultipleSaveMsgResp struct {
-	Code     int64                    `json:"code"`
-	Message  string                   `json:"message"`
-	ErrCount int64                    `json:"errCount"`
-	Data     []map[string]interface{} `json:"data"`
+	Code     int64  `json:"code"`
+	Message  string `json:"message"`
+	ErrCount int64  `json:"errCount"`
 }

+ 6 - 5
api/message.api

@@ -125,13 +125,14 @@ type SendMsgResp {
 
 //批量保存消息
 type MultipleSaveMsgReq {
-	SaveData []map[string]interface{} `json:"saveData"`
+	MsgInfo   map[string]interface{} `json:"msgInfo"`
+	UserIds   string                 `json:"userIds"`
+	UserNames string                 `json:"userNames"`
 }
 type MultipleSaveMsgResp {
-	Code     int64                    `json:"code"`
-	Message  string                   `json:"message"`
-	ErrCount int64                    `json:"errCount"`
-	Data     []map[string]interface{} `json:"data"`
+	Code     int64  `json:"code"`
+	Message  string `json:"message"`
+	ErrCount int64  `json:"errCount"`
 }
 
 service message-api {

+ 47 - 1
api/test/message_test.go

@@ -2,10 +2,14 @@ package test
 
 import (
 	"app.yhyue.com/moapp/MessageCenter/rpc/messageclient"
+	"bytes"
 	"context"
+	"encoding/json"
 	"github.com/tal-tech/go-zero/core/discov"
 	"github.com/tal-tech/go-zero/zrpc"
+	"io/ioutil"
 	"log"
+	"net/http"
 	"testing"
 	"time"
 )
@@ -14,7 +18,7 @@ func  Test_ChangeReadStatus(t *testing.T)  {
 	ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
 	std := messageclient.NewMessage(zrpc.MustNewClient(zrpc.RpcClientConf{Etcd: discov.EtcdConf{Hosts: []string{"127.0.0.1:2379"}, Key: "message.rpc"}}))
 	//std := stdlibclient.NewStdlib(zrpc.MustNewClient(zrpc.RpcClientConf{Etcd: discov.EtcdConf{Hosts: []string{"127.0.0.1:2379"}, Key: "jydocs.stdlib.rpc"}}))
-	req := &messageclient.ChangeReadStatusRequest{Id: 1,ReadStatus: 1,Appid: "10000"}
+	req := &messageclient.ChangeReadStatusRequest{Id: "1",ReadStatus: 1,Appid: "10000"}
 	res, err := std.ChangeReadStatus(ctx, req)
 	log.Println("err ", err,res)
 	//if res.State == true {
@@ -23,3 +27,45 @@ func  Test_ChangeReadStatus(t *testing.T)  {
 	//	log.Println("req false", res)
 	//}
 }
+
+func Test_MultipleSaveMessage(t *testing.T) {
+	msg :=map[string]interface{}{
+		"sendUserId":    "qmx",
+		"sendName":      "剑鱼后台",
+		"title":         "消息标题",
+		"content":       "消息内容",
+		"msgType":       1,
+		"link":          "http://baidu.com",
+		"appid":         "10000",
+	}
+	userIds := "5c00eee91c298a03ab5bd82b,606433f6ad7bab226a81787c"
+	userNames := ","
+	log.Println("调用批量保存消息接口")
+	idsJson, _ := json.Marshal(map[string]interface{}{"msgInfo": msg,"userIds":userIds,"userNames":userNames})
+	reqData := bytes.NewBuffer([]byte(idsJson))
+	url := "http://127.0.0.1:8888/messageCenter/MultipleSaveMsg"
+	method := "POST"
+	client := &http.Client{}
+	req, err := http.NewRequest(method, url, reqData)
+	if err != nil {
+		log.Println(err)
+	}
+	req.Header.Add("Content-Type", "application/json")
+	res, err := client.Do(req)
+	defer res.Body.Close()
+	log.Println(res, err)
+	if err != nil {
+		log.Println("调用批量保存消息接口出错:", err)
+	}
+	body, err := ioutil.ReadAll(res.Body)
+	//log.Println("body", string(body))
+	var dat map[string]interface{}
+	err = json.Unmarshal(body, &dat)
+	log.Println("结果:", dat)
+	if err != nil {
+		log.Println("结果:", err)
+	}
+
+	//errCount = errCount + qutil.IntAll(dat["errCount"])
+	return
+}

+ 2 - 0
entity/message.go

@@ -2,6 +2,7 @@ package entity
 
 import (
 	"app.yhyue.com/moapp/jybase/mysql"
+	"database/sql"
 	clientv3 "go.etcd.io/etcd/client/v3"
 	"time"
 
@@ -12,6 +13,7 @@ import (
 var Engine *xorm.Engine
 var EtcdCli *clientv3.Client
 var Mysql *mysql.Mysql
+var Mysql11 *sql.DB
 
 type Message struct {
 	Id            string       `xorm:"id" form:"id" json:"id"`

+ 0 - 42
rpc/db/config.go

@@ -1,42 +0,0 @@
-package db
-
-import (
-	qutil "app.yhyue.com/moapp/jybase/common"
-	"app.yhyue.com/moapp/jybase/mysql"
-	"log"
-)
-
-var Config *config
-
-type config struct {
-	Mysql mysqlConf
-	Etcd  map[string]interface{}
-}
-
-type mysqlConf struct {
-	DbName       string
-	Address      string
-	UserName     string
-	PassWord     string
-	MaxOpenConns int
-	MaxIdleConns int
-}
-
-var MainMysql *mysql.Mysql
-
-func init() {
-	//程序配置文件
-	qutil.ReadConfig(&Config)
-
-	log.Println("开始初始化数据库。。。。。")
-	//初始化mysql
-	MainMysql = &mysql.Mysql{
-		Address:      Config.Mysql.Address,
-		UserName:     Config.Mysql.UserName,
-		PassWord:     Config.Mysql.PassWord,
-		DBName:       Config.Mysql.DbName,
-		MaxOpenConns: Config.Mysql.MaxOpenConns,
-		MaxIdleConns: Config.Mysql.MaxIdleConns,
-	}
-	MainMysql.Init()
-}

+ 4 - 4
rpc/etc/message.yaml

@@ -2,13 +2,13 @@ Name: message.rpc
 ListenOn: 127.0.0.1:8081
 Etcd:
   Hosts:
-  - 192.168.3.240:2379
-  - 192.168.3.240:2379
+  - 127.0.0.1:2379
+  - 127.0.0.1:2379
   Key: message.rpc
   Timeout: 6000
-Mysql: jianyu:topnet@123@tcp(am-2ze6crwd6bb0283jn167320o.ads.aliyuncs.com:3366)/messageCentertest?timeout=10s&interpolateParams=true
+Mysql: jianyu:topnet@123@tcp(am-2ze6crwd6bb0283jn167320o.ads.aliyuncs.com:3306)/message?timeout=10s&interpolateParams=true
 DataSource:
-    DbName: messageCentertest
+    DbName: message
     Address: am-2ze6crwd6bb0283jn167320o.ads.aliyuncs.com
     UserName: jianyu
     PassWord: topnet@123

BIN
rpc/go_build_message_RPC_go_linux


+ 36 - 0
rpc/internal/logic/multiplesavemsglogic.go

@@ -0,0 +1,36 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/service"
+	"context"
+
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/rpc/message"
+
+	"github.com/tal-tech/go-zero/core/logx"
+)
+
+type MultipleSaveMsgLogic struct {
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+	logx.Logger
+}
+
+func NewMultipleSaveMsgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MultipleSaveMsgLogic {
+	return &MultipleSaveMsgLogic{
+		ctx:    ctx,
+		svcCtx: svcCtx,
+		Logger: logx.WithContext(ctx),
+	}
+}
+
+// 批量保存消息
+func (l *MultipleSaveMsgLogic) MultipleSaveMsg(in *message.MultipleSaveMsgReq) (*message.MultipleSaveMsgResp, error) {
+	// todo: add your logic here and delete this line
+	errCount, msg := service.MultSave(*in)
+	return &message.MultipleSaveMsgResp{
+		Code:     1,
+		Message:  msg,
+		ErrCount: errCount,
+	}, nil
+}

+ 6 - 0
rpc/internal/server/messageserver.go

@@ -21,6 +21,12 @@ func NewMessageServer(svcCtx *svc.ServiceContext) *MessageServer {
 	}
 }
 
+// 批量保存消息
+func (s *MessageServer) MultipleSaveMsg(ctx context.Context, in *message.MultipleSaveMsgReq) (*message.MultipleSaveMsgResp, error) {
+	l := logic.NewMultipleSaveMsgLogic(ctx, s.svcCtx)
+	return l.MultipleSaveMsg(in)
+}
+
 //  修改消息阅读状态
 func (s *MessageServer) ChangeReadStatus(ctx context.Context, in *message.ChangeReadStatusRequest) (*message.Response, error) {
 	l := logic.NewChangeReadStatusLogic(ctx, s.svcCtx)

+ 11 - 11
rpc/message.go

@@ -5,12 +5,12 @@ package main
 
 import (
 	"app.yhyue.com/moapp/MessageCenter/entity"
-	_ "app.yhyue.com/moapp/MessageCenter/rpc/db"
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/config"
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/server"
 	"app.yhyue.com/moapp/MessageCenter/rpc/internal/svc"
 	"app.yhyue.com/moapp/MessageCenter/rpc/message"
 	"app.yhyue.com/moapp/jybase/mysql"
+	"database/sql"
 	"flag"
 	"fmt"
 	"github.com/tal-tech/go-zero/core/conf"
@@ -80,14 +80,14 @@ func init() {
 	//}
 	//fmt.Println(config.ConfigJson.DataSource + "链接成功")
 
-	//entity.Mysql, err = sql.Open("mysql", config.ConfigJson.Mysql)
-	//if err != nil {
-	//	panic(err.Error())
-	//}
-	//// 设置最大打开的连接数,默认值为0,表示不限制。
-	//entity.Mysql.SetMaxOpenConns(5)
-	//// 设置最大闲置的连接数
-	//entity.Mysql.SetMaxIdleConns(5)
-	//// 设置连接的最大生命周期,默认连接总是可重用。
-	//entity.Mysql.SetConnMaxLifetime(time.Hour)
+	entity.Mysql11, err = sql.Open("mysql", config.ConfigJson.Mysql)
+	if err != nil {
+		panic(err.Error())
+	}
+	// 设置最大打开的连接数,默认值为0,表示不限制。
+	entity.Mysql11.SetMaxOpenConns(20)
+	// 设置最大闲置的连接数
+	entity.Mysql11.SetMaxIdleConns(20)
+	// 设置连接的最大生命周期,默认连接总是可重用。
+	entity.Mysql11.SetConnMaxLifetime(time.Hour)
 }

+ 35 - 9
rpc/message.proto

@@ -111,16 +111,16 @@ message GetLastMessageRes {
     Messages data = 3; //
 }
 // 获取用户分类的的未读消息分类及数量 及分类下最新的消息
-message GetUnreadClassCountReq{
-  string userId = 1;    // 用户id
-  string appid = 2;     //应用标识
-  bool needMsg = 3;     //是否需要分类下的最新一条消息
+message GetUnreadClassCountReq {
+    string userId = 1; // 用户id
+    string appid = 2; //应用标识
+    bool needMsg = 3; //是否需要分类下的最新一条消息
 }
-message GetUnreadClassCountRes{
-  int64 code = 1;//状态码
-  string message = 2;//响应消息
-  repeated ResCount data = 3;//
-  repeated Messages info = 4; // 每个类型最新消息列表
+message GetUnreadClassCountRes {
+    int64 code = 1; //状态码
+    string message = 2; //响应消息
+    repeated ResCount data = 3; //
+    repeated Messages info = 4; // 每个类型最新消息列表
 }
 message GetMsgTypeReq {
     string userId = 1; // 用户id
@@ -144,7 +144,33 @@ message UpdateMessageReadResp {
     int64 status = 3;
 }
 
+message user {
+    string userId = 1;
+    string userName = 2;
+}
+
+message multipleSaveMsgReq {
+    string userIds = 1;
+    string userNames = 2;
+    string sendUserId = 3; //发送方用户ID
+    string sendName = 4; //发送方用户名
+    string title = 5; //主题
+    string content = 6; //内容
+    int64 msgType = 7; //消息类型 1:客服   2:系统通知  3:营销   4:用户会话
+    string link = 8; //跳转链接
+    int64 citeId = 9; //引用id
+    string appid = 10; //应用标识
+}
+
+message multipleSaveMsgResp {
+    int64 code = 1; //状态码
+    string message = 2; //响应消息
+    int64 errCount = 3; // 保存出错数量
+}
+
 service Message {
+    //批量保存消息
+    rpc multipleSaveMsg (multipleSaveMsgReq) returns (multipleSaveMsgResp);
     // 修改消息阅读状态
     rpc ChangeReadStatus (ChangeReadStatusRequest) returns (Response);
     //指定用户发消息

+ 433 - 85
rpc/message/message.pb.go

@@ -1549,6 +1549,243 @@ func (x *UpdateMessageReadResp) GetStatus() int64 {
 	return 0
 }
 
+type User struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserId   string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"`
+	UserName string `protobuf:"bytes,2,opt,name=userName,proto3" json:"userName,omitempty"`
+}
+
+func (x *User) Reset() {
+	*x = User{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_message_proto_msgTypes[22]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *User) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*User) ProtoMessage() {}
+
+func (x *User) ProtoReflect() protoreflect.Message {
+	mi := &file_message_proto_msgTypes[22]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use User.ProtoReflect.Descriptor instead.
+func (*User) Descriptor() ([]byte, []int) {
+	return file_message_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *User) GetUserId() string {
+	if x != nil {
+		return x.UserId
+	}
+	return ""
+}
+
+func (x *User) GetUserName() string {
+	if x != nil {
+		return x.UserName
+	}
+	return ""
+}
+
+type MultipleSaveMsgReq struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UserIds    string `protobuf:"bytes,1,opt,name=userIds,proto3" json:"userIds,omitempty"`
+	UserNames  string `protobuf:"bytes,2,opt,name=userNames,proto3" json:"userNames,omitempty"`
+	SendUserId string `protobuf:"bytes,3,opt,name=sendUserId,proto3" json:"sendUserId,omitempty"` //发送方用户ID
+	SendName   string `protobuf:"bytes,4,opt,name=sendName,proto3" json:"sendName,omitempty"`     //发送方用户名
+	Title      string `protobuf:"bytes,5,opt,name=title,proto3" json:"title,omitempty"`           //主题
+	Content    string `protobuf:"bytes,6,opt,name=content,proto3" json:"content,omitempty"`       //内容
+	MsgType    int64  `protobuf:"varint,7,opt,name=msgType,proto3" json:"msgType,omitempty"`      //消息类型 1:客服   2:系统通知  3:营销   4:用户会话
+	Link       string `protobuf:"bytes,8,opt,name=link,proto3" json:"link,omitempty"`             //跳转链接
+	CiteId     int64  `protobuf:"varint,9,opt,name=citeId,proto3" json:"citeId,omitempty"`        //引用id
+	Appid      string `protobuf:"bytes,10,opt,name=appid,proto3" json:"appid,omitempty"`          //应用标识
+}
+
+func (x *MultipleSaveMsgReq) Reset() {
+	*x = MultipleSaveMsgReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_message_proto_msgTypes[23]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MultipleSaveMsgReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MultipleSaveMsgReq) ProtoMessage() {}
+
+func (x *MultipleSaveMsgReq) ProtoReflect() protoreflect.Message {
+	mi := &file_message_proto_msgTypes[23]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MultipleSaveMsgReq.ProtoReflect.Descriptor instead.
+func (*MultipleSaveMsgReq) Descriptor() ([]byte, []int) {
+	return file_message_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *MultipleSaveMsgReq) GetUserIds() string {
+	if x != nil {
+		return x.UserIds
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetUserNames() string {
+	if x != nil {
+		return x.UserNames
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetSendUserId() string {
+	if x != nil {
+		return x.SendUserId
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetSendName() string {
+	if x != nil {
+		return x.SendName
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetTitle() string {
+	if x != nil {
+		return x.Title
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetContent() string {
+	if x != nil {
+		return x.Content
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetMsgType() int64 {
+	if x != nil {
+		return x.MsgType
+	}
+	return 0
+}
+
+func (x *MultipleSaveMsgReq) GetLink() string {
+	if x != nil {
+		return x.Link
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgReq) GetCiteId() int64 {
+	if x != nil {
+		return x.CiteId
+	}
+	return 0
+}
+
+func (x *MultipleSaveMsgReq) GetAppid() string {
+	if x != nil {
+		return x.Appid
+	}
+	return ""
+}
+
+type MultipleSaveMsgResp struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Code     int64  `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`         //状态码
+	Message  string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`    //响应消息
+	ErrCount int64  `protobuf:"varint,3,opt,name=errCount,proto3" json:"errCount,omitempty"` // 保存出错数量
+}
+
+func (x *MultipleSaveMsgResp) Reset() {
+	*x = MultipleSaveMsgResp{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_message_proto_msgTypes[24]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MultipleSaveMsgResp) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MultipleSaveMsgResp) ProtoMessage() {}
+
+func (x *MultipleSaveMsgResp) ProtoReflect() protoreflect.Message {
+	mi := &file_message_proto_msgTypes[24]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MultipleSaveMsgResp.ProtoReflect.Descriptor instead.
+func (*MultipleSaveMsgResp) Descriptor() ([]byte, []int) {
+	return file_message_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *MultipleSaveMsgResp) GetCode() int64 {
+	if x != nil {
+		return x.Code
+	}
+	return 0
+}
+
+func (x *MultipleSaveMsgResp) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *MultipleSaveMsgResp) GetErrCount() int64 {
+	if x != nil {
+		return x.ErrCount
+	}
+	return 0
+}
+
 var File_message_proto protoreflect.FileDescriptor
 
 var file_message_proto_rawDesc = []byte{
@@ -1713,65 +1950,97 @@ var file_message_proto_rawDesc = []byte{
 	0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01,
 	0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73,
 	0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x74, 0x61,
-	0x74, 0x75, 0x73, 0x32, 0x9d, 0x07, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
-	0x47, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61,
-	0x74, 0x75, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x68,
-	0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64,
-	0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x69, 0x6e,
-	0x67, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x65, 0x73,
-	0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x6c,
-	0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x51, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x75, 0x6c, 0x74,
-	0x69, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x25, 0x2e, 0x6d, 0x65,
-	0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x75, 0x6c, 0x74,
-	0x69, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x74, 0x75, 0x73, 0x22, 0x3a, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x75,
+	0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65,
+	0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22,
+	0x94, 0x02, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65,
+	0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64,
+	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73,
+	0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1e,
+	0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a,
+	0x0a, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x73, 0x65, 0x6e, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69,
+	0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65,
+	0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73,
+	0x67, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x73, 0x67,
+	0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x08, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x69, 0x74, 0x65,
+	0x49, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x63, 0x69, 0x74, 0x65, 0x49, 0x64,
+	0x12, 0x14, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x05, 0x61, 0x70, 0x70, 0x69, 0x64, 0x22, 0x5f, 0x0a, 0x13, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70,
+	0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x12, 0x0a,
+	0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x64,
+	0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65,
+	0x72, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65,
+	0x72, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xeb, 0x07, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53,
+	0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67,
+	0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x6d, 0x75,
+	0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73,
+	0x70, 0x12, 0x47, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e,
+	0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x53, 0x65,
+	0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65,
 	0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73,
-	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65,
-	0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x46, 0x69, 0x6e, 0x64,
-	0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x71,
-	0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55,
-	0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65, 0x74,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53,
+	0x69, 0x6e, 0x67, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x2e, 0x6d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x69, 0x6e,
+	0x67, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x75,
+	0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x25, 0x2e,
+	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x75,
+	0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x6e,
+	0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x0b, 0x46, 0x69,
+	0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52,
+	0x65, 0x71, 0x1a, 0x17, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6e,
+	0x64, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x47,
+	0x65, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x12, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74,
 	0x43, 0x6c, 0x61, 0x73, 0x73, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74,
-	0x12, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c,
-	0x61, 0x73, 0x73, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
-	0x71, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55,
-	0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x48, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73,
-	0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47,
-	0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71,
-	0x1a, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61,
-	0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x11,
-	0x46, 0x69, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69,
-	0x6c, 0x12, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73,
-	0x61, 0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65,
-	0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x55,
-	0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12,
-	0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x72,
-	0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71,
-	0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e,
-	0x72, 0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
-	0x73, 0x12, 0x3c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12,
-	0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67,
-	0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
-	0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x73, 0x12,
-	0x52, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
-	0x52, 0x65, 0x61, 0x64, 0x12, 0x1d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55,
-	0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64,
-	0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x55, 0x70,
-	0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52,
-	0x65, 0x73, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65,
+	0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d,
+	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
+	0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74,
+	0x4c, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x12, 0x4a,
+	0x0a, 0x11, 0x46, 0x69, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74,
+	0x61, 0x69, 0x6c, 0x12, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x1a,
+	0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x12, 0x57, 0x0a, 0x13, 0x47, 0x65,
+	0x74, 0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e,
+	0x74, 0x12, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x55,
+	0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52,
+	0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74,
+	0x55, 0x6e, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+	0x52, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70,
+	0x65, 0x12, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d,
+	0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65,
+	0x73, 0x12, 0x52, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65,
+	0x61, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e,
+	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61,
+	0x64, 0x52, 0x65, 0x73, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1786,7 +2055,7 @@ func file_message_proto_rawDescGZIP() []byte {
 	return file_message_proto_rawDescData
 }
 
-var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
+var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
 var file_message_proto_goTypes = []interface{}{
 	(*SendMsgRequest)(nil),               // 0: message.SendMsgRequest
 	(*ChangeReadStatusRequest)(nil),      // 1: message.ChangeReadStatusRequest
@@ -1810,6 +2079,9 @@ var file_message_proto_goTypes = []interface{}{
 	(*GetMsgTypeRes)(nil),                // 19: message.GetMsgTypeRes
 	(*UpdateMessageReadReq)(nil),         // 20: message.UpdateMessageReadReq
 	(*UpdateMessageReadResp)(nil),        // 21: message.UpdateMessageReadResp
+	(*User)(nil),                         // 22: message.user
+	(*MultipleSaveMsgReq)(nil),           // 23: message.multipleSaveMsgReq
+	(*MultipleSaveMsgResp)(nil),          // 24: message.multipleSaveMsgResp
 }
 var file_message_proto_depIdxs = []int32{
 	9,  // 0: message.FindUserMsgRes.data:type_name -> message.Messages
@@ -1817,32 +2089,34 @@ var file_message_proto_depIdxs = []int32{
 	9,  // 2: message.GetLastMessageRes.data:type_name -> message.Messages
 	2,  // 3: message.GetUnreadClassCountRes.data:type_name -> message.ResCount
 	9,  // 4: message.GetUnreadClassCountRes.info:type_name -> message.Messages
-	1,  // 5: message.Message.ChangeReadStatus:input_type -> message.ChangeReadStatusRequest
-	0,  // 6: message.Message.SendUserMsg:input_type -> message.SendMsgRequest
-	3,  // 7: message.Message.DeleteSingleMessage:input_type -> message.DeleteSingleMessageRequest
-	4,  // 8: message.Message.DeleteMultipleMessage:input_type -> message.DeleteMultipleMessageRequest
-	5,  // 9: message.Message.GetUnreadCount:input_type -> message.GetUnreadCountRequest
-	8,  // 10: message.Message.FindUserMsg:input_type -> message.FindUserMsgReq
-	11, // 11: message.Message.GetClassUnreadCount:input_type -> message.GetClassUnreadCountReq
-	14, // 12: message.Message.GetLastMessage:input_type -> message.GetLastMessageReq
-	12, // 13: message.Message.FindMessageDetail:input_type -> message.MessageDetailReq
-	16, // 14: message.Message.GetUnreadClassCount:input_type -> message.GetUnreadClassCountReq
-	18, // 15: message.Message.GetMsgType:input_type -> message.GetMsgTypeReq
-	20, // 16: message.Message.UpdateMessageRead:input_type -> message.UpdateMessageReadReq
-	6,  // 17: message.Message.ChangeReadStatus:output_type -> message.Response
-	6,  // 18: message.Message.SendUserMsg:output_type -> message.Response
-	6,  // 19: message.Message.DeleteSingleMessage:output_type -> message.Response
-	6,  // 20: message.Message.DeleteMultipleMessage:output_type -> message.Response
-	7,  // 21: message.Message.GetUnreadCount:output_type -> message.GetUnreadCountResponse
-	10, // 22: message.Message.FindUserMsg:output_type -> message.FindUserMsgRes
-	7,  // 23: message.Message.GetClassUnreadCount:output_type -> message.GetUnreadCountResponse
-	15, // 24: message.Message.GetLastMessage:output_type -> message.GetLastMessageRes
-	13, // 25: message.Message.FindMessageDetail:output_type -> message.MessageDetailResp
-	17, // 26: message.Message.GetUnreadClassCount:output_type -> message.GetUnreadClassCountRes
-	19, // 27: message.Message.GetMsgType:output_type -> message.GetMsgTypeRes
-	21, // 28: message.Message.UpdateMessageRead:output_type -> message.UpdateMessageReadResp
-	17, // [17:29] is the sub-list for method output_type
-	5,  // [5:17] is the sub-list for method input_type
+	23, // 5: message.Message.multipleSaveMsg:input_type -> message.multipleSaveMsgReq
+	1,  // 6: message.Message.ChangeReadStatus:input_type -> message.ChangeReadStatusRequest
+	0,  // 7: message.Message.SendUserMsg:input_type -> message.SendMsgRequest
+	3,  // 8: message.Message.DeleteSingleMessage:input_type -> message.DeleteSingleMessageRequest
+	4,  // 9: message.Message.DeleteMultipleMessage:input_type -> message.DeleteMultipleMessageRequest
+	5,  // 10: message.Message.GetUnreadCount:input_type -> message.GetUnreadCountRequest
+	8,  // 11: message.Message.FindUserMsg:input_type -> message.FindUserMsgReq
+	11, // 12: message.Message.GetClassUnreadCount:input_type -> message.GetClassUnreadCountReq
+	14, // 13: message.Message.GetLastMessage:input_type -> message.GetLastMessageReq
+	12, // 14: message.Message.FindMessageDetail:input_type -> message.MessageDetailReq
+	16, // 15: message.Message.GetUnreadClassCount:input_type -> message.GetUnreadClassCountReq
+	18, // 16: message.Message.GetMsgType:input_type -> message.GetMsgTypeReq
+	20, // 17: message.Message.UpdateMessageRead:input_type -> message.UpdateMessageReadReq
+	24, // 18: message.Message.multipleSaveMsg:output_type -> message.multipleSaveMsgResp
+	6,  // 19: message.Message.ChangeReadStatus:output_type -> message.Response
+	6,  // 20: message.Message.SendUserMsg:output_type -> message.Response
+	6,  // 21: message.Message.DeleteSingleMessage:output_type -> message.Response
+	6,  // 22: message.Message.DeleteMultipleMessage:output_type -> message.Response
+	7,  // 23: message.Message.GetUnreadCount:output_type -> message.GetUnreadCountResponse
+	10, // 24: message.Message.FindUserMsg:output_type -> message.FindUserMsgRes
+	7,  // 25: message.Message.GetClassUnreadCount:output_type -> message.GetUnreadCountResponse
+	15, // 26: message.Message.GetLastMessage:output_type -> message.GetLastMessageRes
+	13, // 27: message.Message.FindMessageDetail:output_type -> message.MessageDetailResp
+	17, // 28: message.Message.GetUnreadClassCount:output_type -> message.GetUnreadClassCountRes
+	19, // 29: message.Message.GetMsgType:output_type -> message.GetMsgTypeRes
+	21, // 30: message.Message.UpdateMessageRead:output_type -> message.UpdateMessageReadResp
+	18, // [18:31] is the sub-list for method output_type
+	5,  // [5:18] is the sub-list for method input_type
 	5,  // [5:5] is the sub-list for extension type_name
 	5,  // [5:5] is the sub-list for extension extendee
 	0,  // [0:5] is the sub-list for field type_name
@@ -2118,6 +2392,42 @@ func file_message_proto_init() {
 				return nil
 			}
 		}
+		file_message_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*User); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_message_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MultipleSaveMsgReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_message_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MultipleSaveMsgResp); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -2125,7 +2435,7 @@ func file_message_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_message_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   22,
+			NumMessages:   25,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
@@ -2151,6 +2461,8 @@ const _ = grpc.SupportPackageIsVersion6
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
 type MessageClient interface {
+	//批量保存消息
+	MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsgReq, opts ...grpc.CallOption) (*MultipleSaveMsgResp, error)
 	// 修改消息阅读状态
 	ChangeReadStatus(ctx context.Context, in *ChangeReadStatusRequest, opts ...grpc.CallOption) (*Response, error)
 	//指定用户发消息
@@ -2185,6 +2497,15 @@ func NewMessageClient(cc grpc.ClientConnInterface) MessageClient {
 	return &messageClient{cc}
 }
 
+func (c *messageClient) MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsgReq, opts ...grpc.CallOption) (*MultipleSaveMsgResp, error) {
+	out := new(MultipleSaveMsgResp)
+	err := c.cc.Invoke(ctx, "/message.Message/multipleSaveMsg", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *messageClient) ChangeReadStatus(ctx context.Context, in *ChangeReadStatusRequest, opts ...grpc.CallOption) (*Response, error) {
 	out := new(Response)
 	err := c.cc.Invoke(ctx, "/message.Message/ChangeReadStatus", in, out, opts...)
@@ -2295,6 +2616,8 @@ func (c *messageClient) UpdateMessageRead(ctx context.Context, in *UpdateMessage
 
 // MessageServer is the server API for Message service.
 type MessageServer interface {
+	//批量保存消息
+	MultipleSaveMsg(context.Context, *MultipleSaveMsgReq) (*MultipleSaveMsgResp, error)
 	// 修改消息阅读状态
 	ChangeReadStatus(context.Context, *ChangeReadStatusRequest) (*Response, error)
 	//指定用户发消息
@@ -2325,6 +2648,9 @@ type MessageServer interface {
 type UnimplementedMessageServer struct {
 }
 
+func (*UnimplementedMessageServer) MultipleSaveMsg(context.Context, *MultipleSaveMsgReq) (*MultipleSaveMsgResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method MultipleSaveMsg not implemented")
+}
 func (*UnimplementedMessageServer) ChangeReadStatus(context.Context, *ChangeReadStatusRequest) (*Response, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method ChangeReadStatus not implemented")
 }
@@ -2366,6 +2692,24 @@ func RegisterMessageServer(s *grpc.Server, srv MessageServer) {
 	s.RegisterService(&_Message_serviceDesc, srv)
 }
 
+func _Message_MultipleSaveMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MultipleSaveMsgReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MessageServer).MultipleSaveMsg(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/message.Message/MultipleSaveMsg",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MessageServer).MultipleSaveMsg(ctx, req.(*MultipleSaveMsgReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _Message_ChangeReadStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(ChangeReadStatusRequest)
 	if err := dec(in); err != nil {
@@ -2586,6 +2930,10 @@ var _Message_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "message.Message",
 	HandlerType: (*MessageServer)(nil),
 	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "multipleSaveMsg",
+			Handler:    _Message_MultipleSaveMsg_Handler,
+		},
 		{
 			MethodName: "ChangeReadStatus",
 			Handler:    _Message_ChangeReadStatus_Handler,

+ 28 - 17
rpc/messageclient/message.go

@@ -14,30 +14,35 @@ import (
 )
 
 type (
-	DeleteSingleMessageRequest   = message.DeleteSingleMessageRequest
-	FindUserMsgReq               = message.FindUserMsgReq
-	FindUserMsgRes               = message.FindUserMsgRes
-	GetMsgTypeReq                = message.GetMsgTypeReq
-	GetMsgTypeRes                = message.GetMsgTypeRes
-	UpdateMessageReadResp        = message.UpdateMessageReadResp
-	Response                     = message.Response
-	GetClassUnreadCountReq       = message.GetClassUnreadCountReq
-	SendMsgRequest               = message.SendMsgRequest
-	ChangeReadStatusRequest      = message.ChangeReadStatusRequest
 	ResCount                     = message.ResCount
-	Messages                     = message.Messages
 	GetLastMessageRes            = message.GetLastMessageRes
-	GetUnreadClassCountRes       = message.GetUnreadClassCountRes
-	UpdateMessageReadReq         = message.UpdateMessageReadReq
+	MultipleSaveMsgReq           = message.MultipleSaveMsgReq
+	FindUserMsgRes               = message.FindUserMsgRes
+	MessageDetailResp            = message.MessageDetailResp
+	GetUnreadClassCountReq       = message.GetUnreadClassCountReq
+	User                         = message.User
 	DeleteMultipleMessageRequest = message.DeleteMultipleMessageRequest
-	GetUnreadCountRequest        = message.GetUnreadCountRequest
+	FindUserMsgReq               = message.FindUserMsgReq
+	Messages                     = message.Messages
+	GetLastMessageReq            = message.GetLastMessageReq
+	UpdateMessageReadReq         = message.UpdateMessageReadReq
+	SendMsgRequest               = message.SendMsgRequest
+	ChangeReadStatusRequest      = message.ChangeReadStatusRequest
+	GetClassUnreadCountReq       = message.GetClassUnreadCountReq
 	GetUnreadCountResponse       = message.GetUnreadCountResponse
 	MessageDetailReq             = message.MessageDetailReq
-	MessageDetailResp            = message.MessageDetailResp
-	GetLastMessageReq            = message.GetLastMessageReq
-	GetUnreadClassCountReq       = message.GetUnreadClassCountReq
+	GetUnreadClassCountRes       = message.GetUnreadClassCountRes
+	GetMsgTypeReq                = message.GetMsgTypeReq
+	GetMsgTypeRes                = message.GetMsgTypeRes
+	DeleteSingleMessageRequest   = message.DeleteSingleMessageRequest
+	GetUnreadCountRequest        = message.GetUnreadCountRequest
+	Response                     = message.Response
+	UpdateMessageReadResp        = message.UpdateMessageReadResp
+	MultipleSaveMsgResp          = message.MultipleSaveMsgResp
 
 	Message interface {
+		// 批量保存消息
+		MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsgReq) (*MultipleSaveMsgResp, error)
 		//  修改消息阅读状态
 		ChangeReadStatus(ctx context.Context, in *ChangeReadStatusRequest) (*Response, error)
 		// 指定用户发消息
@@ -75,6 +80,12 @@ func NewMessage(cli zrpc.Client) Message {
 	}
 }
 
+// 批量保存消息
+func (m *defaultMessage) MultipleSaveMsg(ctx context.Context, in *MultipleSaveMsgReq) (*MultipleSaveMsgResp, error) {
+	client := message.NewMessageClient(m.cli.Conn())
+	return client.MultipleSaveMsg(ctx, in)
+}
+
 //  修改消息阅读状态
 func (m *defaultMessage) ChangeReadStatus(ctx context.Context, in *ChangeReadStatusRequest) (*Response, error) {
 	client := message.NewMessageClient(m.cli.Conn())

+ 73 - 2
rpc/test/send_test.go

@@ -1,7 +1,10 @@
 package test
 
 import (
+	"app.yhyue.com/moapp/MessageCenter/rpc/internal/config"
 	"context"
+	"database/sql"
+	"fmt"
 	"log"
 	"testing"
 	"time"
@@ -39,8 +42,8 @@ func Test_FindUserMsg(t *testing.T) {
 		UserId:        "5fa3bb6d059e75bcdf8dab6a",
 		OffSet:        int64(0),
 		PageSize:      int64(10),
-		MsgType: -1,
-		Read: -1,
+		MsgType:       -1,
+		Read:          -1,
 	}
 	res, err := std.FindUserMsg(ctx, req)
 	log.Println("err ", err, res.Code, res.Message, res.Count, res.Data)
@@ -57,3 +60,71 @@ func Test_ClassUnread(t *testing.T) {
 	res, err := std.GetClassUnreadCount(ctx, req)
 	log.Println("err ", err, res)
 }
+
+func Test_InsertMsg(t *testing.T) {
+	url := fmt.Sprintf(config.ConfigJson.Mysql)
+	db, err := sql.Open("mysql", url)
+	if err != nil {
+		panic(err.Error())
+	}
+	// 设置最大打开的连接数,默认值为0,表示不限制。
+	db.SetMaxOpenConns(5)
+	// 设置最大闲置的连接数
+	db.SetMaxIdleConns(5)
+	// 设置连接的最大生命周期,默认连接总是可重用。
+	// 不能保证连接将在池中存在完整的一小时;很可能由于某种原因连接将变得不可用,并且在此之前自动关闭.
+	// 这不是空闲超时。连接将在第1次创建后1小时后过期,而不是1小时后变成空闲。
+	// 理论上,ConnMaxLifetime越短,从0开始创建连接的频率就越高。
+	db.SetConnMaxLifetime(time.Hour)
+	defer db.Close()
+	stmt, err := db.Prepare("select * from student where id = ?")
+	if err != nil {
+		panic(err.Error())
+	}
+	defer stmt.Close()
+	rows, err := stmt.Query(9)
+	if err != nil {
+		panic(err.Error())
+	}
+	defer rows.Close()
+	for rows.Next() {
+		var id string
+		var name string
+		var unit string
+		err := rows.Scan(&id, &name, &unit)
+		if err != nil {
+			panic(err.Error())
+		}
+		fmt.Println(fmt.Sprintf("%s, %s, %s", id, name, unit))
+	}
+}
+
+func Test_SaveMsg(t *testing.T) {
+	ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
+	std := messageclient.NewMessage(zrpc.MustNewClient(zrpc.RpcClientConf{Etcd: discov.EtcdConf{Hosts: []string{"127.0.0.1:2379"}, Key: "message.rpc"}}))
+
+	req := &messageclient.MultipleSaveMsgReq{
+		Appid:      "10000",
+		MsgType:    4,
+		Title:      "11",
+		Content:    "22",
+		Link:       "",
+		CiteId:     0,
+		SendUserId: "111",
+		SendName:   "222",
+		UserNames:  ",",
+		UserIds:    "111,2222",
+	}
+	res, err := std.MultipleSaveMsg(ctx, req)
+	log.Println("err ", err, res)
+}
+
+//repeated user userInfo = 1;
+//string sendUserId = 2; //发送方用户ID
+//string sendName = 3; //发送方用户名
+//string title = 4; //主题
+//string content = 5; //内容
+//int64 msgType = 6; //消息类型 1:客服   2:系统通知  3:营销   4:用户会话
+//string link = 7; //跳转链接
+//int64 citeId = 8; //引用id
+//string appid = 9; /

+ 77 - 6
service/sendMsg.go

@@ -8,6 +8,7 @@ import (
 	"go.etcd.io/etcd/client/v3/concurrency"
 	"log"
 	"strconv"
+	"strings"
 	"time"
 
 	"app.yhyue.com/moapp/MessageCenter/entity"
@@ -23,25 +24,37 @@ func SendMsg(this message.SendMsgRequest) (int64, string) {
 	//defer orm.Close()
 	//err := orm.Begin()
 	//fmt.Println(err)
-	count := entity.Mysql.Count("conversation", map[string]interface{}{"receive_id": this.ReceiveUserId, "send_id": this.SendUserId})
+	//count := entity.Mysql11.Query("conversation", map[string]interface{}{"receive_id": this.ReceiveUserId, "send_id": this.SendUserId})
+
+	r, err := entity.Mysql11.Query("select count(*) as c from conversation where receive_id = ? and send_id = ? ", this.ReceiveUserId, this.SendUserId)
+	c := 0
+	log.Println("查询结果", r)
+	for r.Next() {
+		err := r.Scan(&c)
+		if err != nil {
+			panic(err.Error())
+		}
+	}
+
+	log.Println("查询数量:", c)
 
 	sql3 := `INSERT INTO message(appid,receive_userid,receive_name,send_userid,send_name,title,content,msg_type,link,cite_id,createtime,isRead,isdel)
 		values ("%s",'%s','%s','%s','%s','%s','%s','%d','%s',0,'%s',0,1);`
 	sql3 = fmt.Sprintf(sql3, this.Appid, this.ReceiveUserId, this.ReceiveName, this.SendUserId, this.SendName, this.Title, this.Content, this.MsgType, this.Link, time.Now().Format("2006-01-02 15:04:05"))
-	if count < 1 {
+	if c < 1 {
 		sql1 := `INSERT INTO conversation(appid,` + "`key`" + `,user_id,receive_id,receive_name,send_id,send_name,sort,createtime) 
 		values ('%s','','%s','%s','%s','%s','%s',0,'%s');`
 		sql1 = fmt.Sprintf(sql1, this.Appid, this.SendUserId, this.ReceiveUserId, this.ReceiveName, this.SendUserId, this.SendName, time.Now().Format("2006-01-02 15:04:05"))
 		ok := entity.Mysql.ExecTx("发送消息事务", func(tx *sql.Tx) bool {
 			//插入会话表
-			_, err := entity.Mysql.DB.Exec(sql1)
+			_, err := entity.Mysql11.Exec(sql1)
 
 			sql2 := `INSERT INTO conversation(appid,` + "`key`" + `,user_id,receive_id,receive_name,send_id,send_name,sort,createtime) 
 		values ('%s','','%s','%s','%s','%s','%s',0,'%s');`
 			sql2 = fmt.Sprintf(sql2, this.Appid, this.ReceiveUserId, this.SendUserId, this.SendName, this.ReceiveUserId, this.ReceiveName, time.Now().Format("2006-01-02 15:04:05"))
-			_, err = entity.Mysql.DB.Exec(sql2)
+			_, err = entity.Mysql11.Exec(sql2)
 			//插入消息表
-			_, err = entity.Mysql.DB.Exec(sql3)
+			_, err = entity.Mysql11.Exec(sql3)
 			if err != nil {
 				return false
 			}
@@ -51,7 +64,7 @@ func SendMsg(this message.SendMsgRequest) (int64, string) {
 			return 1, "消息发送成功"
 		}
 	}
-	_, err := entity.Mysql.DB.Exec(sql3)
+	_, err = entity.Mysql11.Exec(sql3)
 	if err == nil {
 		go EtcdCountAdd(this.ReceiveUserId, strconv.Itoa(int(this.MsgType)))
 		return 1, "消息发送成功"
@@ -275,3 +288,61 @@ func EtcdSetCountZero(userId, msgType string) {
 		log.Fatal("释放锁失败", err)
 	}
 }
+
+func MultSave(this message.MultipleSaveMsgReq) (int64, string) {
+	userIdArr := strings.Split(this.UserIds, ",")
+	userNameArr := strings.Split(this.UserNames, ",")
+	log.Println(len(userIdArr), len(userNameArr))
+	if len(userIdArr) > 0 {
+		var errCount int64
+		for k, v := range userIdArr {
+			log.Println("k--------", k, v)
+			if v == "" {
+				return 0, "调用结束"
+			}
+			userName := userNameArr[k]
+			//消息数组
+			c := entity.Mysql.Count("conversation", map[string]interface{}{"receive_id": v, "send_id": this.SendUserId})
+			log.Println("查询数量:", c)
+			sql3 := `INSERT INTO message(appid,receive_userid,receive_name,send_userid,send_name,title,content,msg_type,link,cite_id,createtime,isRead,isdel) values ("%s",'%s','%s','%s','%s','%s','%s','%d','%s',0,'%s',0,1);`
+			sql3 = fmt.Sprintf(sql3, this.Appid, v, userName, this.SendUserId, this.SendName, this.Title, this.Content, this.MsgType, this.Link, time.Now().Format("2006-01-02 15:04:05"))
+			if c < 1 {
+				sql1 := `INSERT INTO conversation(appid,` + "`key`" + `,user_id,receive_id,receive_name,send_id,send_name,sort,createtime) values ('%s','','%s','%s','%s','%s','%s',0,'%s');`
+				sql1 = fmt.Sprintf(sql1, this.Appid, this.SendUserId, v, userName, this.SendUserId, this.SendName, time.Now().Format("2006-01-02 15:04:05"))
+				ok := entity.Mysql.ExecTx("发送消息事务", func(tx *sql.Tx) bool {
+					//插入会话表
+					bT := time.Now() //开始时间
+					_, err := entity.Mysql.DB.Exec(sql1)
+					log.Println("**********1",err)
+					sql2 := `INSERT INTO conversation(appid,` + "`key`" + `,user_id,receive_id,receive_name,send_id,send_name,sort,createtime) values ('%s','','%s','%s','%s','%s','%s',0,'%s');`
+					sql2 = fmt.Sprintf(sql2, this.Appid, v, this.SendUserId, this.SendName, v, userName, time.Now().Format("2006-01-02 15:04:05"))
+					_, err = entity.Mysql.DB.Exec(sql2)
+					log.Println("**********2",err)
+					//插入消息表
+					_, err = entity.Mysql.DB.Exec(sql3)
+					eT := time.Since(bT) // 从开始到当前所消耗的时间
+					log.Println("存储耗时:", eT)
+					if err != nil {
+						return false
+					}
+					return true
+				})
+				if !ok {
+					errCount++
+					continue
+				}
+				go EtcdCountAdd(v, strconv.Itoa(int(this.MsgType)))
+
+			} else {
+				_, err := entity.Mysql.DB.Exec(sql3)
+				if err == nil {
+					go EtcdCountAdd(v, strconv.Itoa(int(this.MsgType)))
+				} else {
+					errCount++
+				}
+			}
+		}
+		return errCount, "发送成功"
+	}
+	return 0, "没有要发送的用户"
+}