一、文章前言
此文主要实现在小程序内聊天对话功能,使用C#作为后端语言进行支持,界面友好,开发简单。
二、开发流程及准备
2.1、注册微信公众平台账号。
2.2、下载安装Visual Studio(后端语言开发工具),SQL Server数据库,微信Web开发者工具。
三、开发步骤
3.1、打开Visual Studio,创建新项目,选择ASP.NET Web应用程序(.NET Framework)。
3.2、填写项目名称及选择对应的保存位置,框架版本我们这里选择4.7.2。
3.3、这一步骤我们选择MVC,因为我们主要是用它来搭建API接口,其他的选项默认即可。
3.4、创建完成后,显示这个界面就证明第一步完成了,右边的就是传统MVC架构方案。
3.5、打开SQL Server创建数据库及对应的表用于存储数据。(可以先插入两条测试数据)
--创建数据库
CREATE DATABASE Chat;
--选中数据库
USE Chat;
--创建数据表
CREATE TABLE ChatRecord(
id INT PRIMARY KEY IDENTITY, --记录编号,主键自增
userName NVARCHAR(50), --用户名
content NVARCHAR(255), --聊天内容
createTime DATETIME, --发送时间
red INT --读取状态 0未读 1已读
);
INSERT INTO ChatRecord VALUES('小咪','喵喵喵!喵喵喵!喵喵喵!喵喵!喵喵!!喵!喵喵喵!',GETDATE(),0);
INSERT INTO ChatRecord VALUES('小汪','汪汪汪!汪汪汪!汪汪汪!',GETDATE(),0);
3.6、回到Visual Studio,选择Models文件夹,Model在MVC中就是M,也就是实体,然后点击添加,选择新建项。
3.7、右上方搜索框输入实体数据模型,选择然后点击添加。
3.8、选择来自数据库的EF设计器,点击下一步。
3.9、数据源选择Microsoft SQL Server,点击继续。
3.10、在服务器名文本框输入一个" . ",在这里代表的是本机的意思,输入之后在下面的选择数据库下拉框选择我们上面所创建的Chat数据库。
3.11、选择对应的实体框架版本,这里选择5.0跟6.x都可以,点击下一步。
3.12、我们这里只创建了数据表,只需要选择表就可以,点击完成,即可生成对应的实体数据模型。
3.13、选择Models文件夹,选择添加,点击类,建立一个上下文类,用于帮助我们操作数据库。这里需要注意引入命名空间。
/// <summary>
/// 获取上下文
/// </summary>
/// <returns>EF上下文</returns>
public static ChatEntities Create()
{
ChatEntities db = CallContext.GetData("db") as ChatEntities;
if (db == null)
{
db = new ChatEntities();
CallContext.SetData("db", db);
}
return db;
}
3.14、继续选择Models文件夹,新建一个Services类,编写我们的业务逻辑代码,Linq语法我们这里就不一一赘述了,这里我们主要实现根据创建时间排序查询聊天记录及新增聊天记录的两个方法。
/// <summary>
/// 定义返回数据帮助类
/// </summary>
public class JsonResult
{
/// <summary>
/// 状态码 0 失败 1成功
/// </summary>
public int Code { get; set; }
/// <summary>
/// 提示消息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 数据
/// </summary>
public object Data { get; set; }
}
// 查询聊天记录列表
public static JsonResult GetChatRecord()
{
JsonResult res = new JsonResult() { Code = 0, Msg = "暂无数据" };
var db = BaseModel.Create();
//使用linq根据创建时间排序返回消息记录
var list = db.ChatRecord.OrderBy(x => x.createTime).ToList();
res.Code = 1;
res.Msg = "查询成功";
res.Data = list;
return res;
}
// 新增消息
public static JsonResult AddChatRecord(ChatRecord jsonData)
{
JsonResult res = new JsonResult() { Code = 0, Msg = "发送失败" };
var db = BaseModel.Create();
ChatRecord info = new ChatRecord();
info.userName = jsonData.userName;
info.content = jsonData.content;
info.createTime = DateTime.Now;
info.red = 0;
db.ChatRecord.Add(info);
if (db.SaveChanges() > 0)
{
res.Code = 1;
res.Msg = "发送成功";
return res;
}
return res;
}
3.15、业务代码编写完毕后,我们需要在控制器进行调用,这里需要引入Models的命名空间。
/// <summary>
/// 查询聊天记录
/// </summary>
/// <returns></returns>
public ActionResult GetChatRecord()
{
return Json(Services.GetChatRecord(), JsonRequestBehavior.AllowGet);
}
/// <summary>
/// 新增聊天
/// </summary>
/// <param name="jsonData"></param>
/// <returns></returns>
public ActionResult AddChatRecord(ChatRecord jsonData)
{
return Json(Services.AddChatRecord(jsonData));
}
3.16、点击顶上方的调试、开始执行(不调试按钮),启动项目,打开的是默认的Index界面。
3.17、通过URL访问对应的控制器/动作方法,测试接口是否能够正常访问。
3.18、可以看到接口数据能够正常返回,就是我们在创建数据库时所添加的两条测试数据,但是创建时间返回的是时间戳模式,我们需要在返回数据的时候进行一下处理。
public static JsonResult GetChatRecord()
{
JsonResult res = new JsonResult() { Code = 0, Msg = "暂无数据" };
var db = BaseModel.Create();
//使用linq根据创建时间排序返回消息记录
var list = db.ChatRecord.OrderBy(x => x.createTime).ToList().Select(x => new {
x.userName,
x.content,
createTime = Convert.ToDateTime(x.createTime).ToString("yyyy-MM-dd:hh:mm"),//时间戳转换为yyyyMMdd:hh:mm
});
res.Code = 1;
res.Msg = "查询成功";
res.Data = list;
return res;
}
3.19、接口能够正常访问后,我们就可以开始小程序的开发了,打开微信开发者工具,新建项目,选择不使用模板、不使用云服务。
3.20、在pages文件夹下面创建一个文件夹并新建对应的page文件,并实现聊天对话框样式。
<view class="cu-chat" id="j_page">
<view class="cu-item 'self'" wx:for="{{chatData}}">
<view class="main">
<view class="content shadow bg-green">
<text>{{item.content}}</text>
</view>
</view>
<view class="cu-avatar radius" style="background-image:url(../../../images/cat.jpg)"></view>
<view class="date">{{item.createTime}}</view>
</view>
</view>
<view class="cu-bar foot input {{InputBottom!=0?'cur':''}}" style="bottom:{{InputBottom}}px">
<view class="action">
<text class="cuIcon-sound text-grey"></text>
</view>
<input class="solid-bottom" value="{{content}}" bindinput="formMsg" bindfocus="InputFocus" bindblur="InputBlur" adjust-position="{{false}}" focus="{{false}}" maxlength="300" cursor-spacing="10"></input>
<view class="action">
<text class="cuIcon-emojifill text-grey"></text>
</view>
<button class="cu-btn bg-green shadow" bindtap="sendMsg">发送</button>
</view>
.cu-chat {
display: flex;
flex-direction: column;
}
.cu-chat .cu-item {
display: flex;
padding: 30rpx 30rpx 70rpx;
position: relative;
}
.cu-chat .cu-item>.cu-avatar {
width: 80rpx;
height: 80rpx;
}
.cu-chat .cu-item>.main {
max-width: calc(100% - 260rpx);
margin: 0 40rpx;
display: flex;
align-items: center;
}
.cu-chat .cu-item>image {
height: 320rpx;
}
.cu-chat .cu-item>.main .content {
padding: 20rpx;
border-radius: 6rpx;
display: inline-flex;
max-width: 100%;
align-items: center;
font-size: 30rpx;
position: relative;
min-height: 80rpx;
line-height: 40rpx;
text-align: left;
}
.cu-chat .cu-item>.main .content:not([class*="bg-"]) {
background-color: var(--white);
color: var(--black);
}
.cu-chat .cu-item .date {
position: absolute;
font-size: 24rpx;
color: var(--grey);
width: calc(100% - 320rpx);
bottom: 20rpx;
left: 160rpx;
}
.cu-chat .cu-item .action {
padding: 0 30rpx;
display: flex;
align-items: center;
}
.cu-chat .cu-item>.main .content::after {
content: "";
top: 27rpx;
transform: rotate(45deg);
position: absolute;
z-index: 100;
display: inline-block;
overflow: hidden;
width: 24rpx;
height: 24rpx;
left: -12rpx;
right: initial;
background-color: inherit;
}
.cu-chat .cu-item.self>.main .content::after {
left: auto;
right: -12rpx;
}
3.21、在JS中实现请求聊天列表及新增聊天信息的接口,请求接口时可以设一个定时器,每隔多少秒请求一次消息,新增消息时先将用户名写死,后续可以更改为获取用户token。实现新增聊天信息的时候需要给文本框绑定对应的bindinput事件,每次用户有编辑时即获取文本框的值存储到data中。
setInterval(function () {
wx.request({
url: 'https://localhost:44382/home/GetChatRecord',
method: 'post',
dataType: "json",
success: function (res) {
that.setData({
chatData: res.data.Data
});
}
});
}, 1000);
formMsg(e) {
this.setData({
content: e.detail.value.trim()
})
},
let info = {
userName: '小咪',
content: that.data.content,
};
wx.request({
url: 'https://localhost:44382/home/AddChatRecord',
data: info,
method: 'post',
dataType: "json",
success: function (identify) {
that.setData({
content: '',
});
//发送消息后 刷新数据
wx.request({
url: 'https://localhost:44382/home/GetChatRecord',
method: 'post',
dataType: "json",
success: function (res) {
that.setData({
chatData: res.data.Data
});
}
});
}
});
3.22、准备两张头像,在WXML中根据对应的用户名判断聊天记录是否是自己发出,并赋对应的class样式,后续这个步骤可以直接在接口返回的数据中进行判断,请求查询列表的接口将用户token作为参数传输过去即可。
<view class="cu-chat" id="j_page">
<view class="cu-item {{item.userName=='小咪'?'self':''}}" wx:for="{{chatData}}">
<view class="cu-avatar radius" style="background-image:url(../../../images/dog.jpg)" wx:if="{{item.userName=='小汪'}}"></view>
<view class="main">
<view class="content shadow {{item.userName=='小咪'?'bg-green':''}}">
<text>{{item.content}}</text>
</view>
</view>
<view class="cu-avatar radius" style="background-image:url(../../../images/cat.jpg)" wx:if="{{item.userName=='小咪'}}"></view>
<view class="date">{{item.createTime}}</view>
</view>
</view>
3.23、请求聊天记录的接口和新增聊天信息的接口都跑通后,我们将现有小程序复制一份,在复制出的这份小程序中的JS将用户名改为小汪,然后发送消息。这里需要注意的是,我们需要在每次发送消息后将页面内容定位在底部,一直保持一个阅读最新消息的状态。
wx.pageScrollTo({
scrollTop: 9999
})
这里采用的一个比较简单的方式实现的聊天功能,性能及设计方面有很大的提升空间,后续会用ws长连接或者接入第三方插件的方式来实现这个功能,完成后源码会以资源的形式上传提供给大家。