Nicht mehr gepflegt
Dieses Projekt wurde beim Studium geschrieben, und einige Orte sind schlecht lesbar (z. B. eine große Anzahl von Rückrufen im Mongo -Teil). Schüler, die es brauchen, lesen es sorgfältig, danke.
Der Filiale ist online und wurde entsprechend geändert. Wenn Sie standardmäßig einer Chat -Gruppe beitreten und sich das Backend an einige Linux -Codeanpassungen anpassen kann, wird empfohlen, den Master zu ziehen.
Beachten Sie, dass es Knoten, NPM und MongoDB geben muss. Die Standard -IP -Adresse des Projekts mongoDB lautet 127.0.0.1:27017, die in der Konfigurationsdatei geändert werden kann. (Chatserver utils database.js)
cd chatRoom
npm install 安装前端依赖
npm run build 编译前端代码
cd ..
cd chatServer
npm install 安装后端依赖
npm run create 初始化数据库(号码池、表情包)
npm start 启动服务
在浏览器中打开 localhost:9988 即可
Das Projekt begann, weil die Arbeit eine Chatroom -Funktion erforderte, aber aus irgendeinen Gründen habe ich mich schließlich auf der Grundlage des XMPP -Protokolls entschieden. Also wollte ich selbst einen Satz davon mit Knoten schreiben. Ich wollte ursprünglich einfach eine Chat -Seite schreiben, aber ich war nicht zufrieden, nachdem ich sie geschrieben habe, also habe ich sie weiter nachgearbeitet (es scheint, dass ich verstehen kann, warum der Produktmanager die Bedürfnisse immer geändert hat).
Viele Dinge wie MongoDB sind auch das erste Mal, dass ich sie benutzte. Ich war erst zuvor MySQL ausgesetzt. Also habe ich gleichzeitig gelernt und geschrieben. Ich habe meine Freizeit für mehrere Monate lang zeitweise geschrieben (diesmal habe ich über die Version v0.9.0 gesprochen und das Projekt wird noch aktualisiert ...), das einen vollständigen Satz von Front-End- und Back-End-Interaktionen enthält. Die Benutzeroberfläche kommt aus meinen eigenen Gefühlen und hat kein Design-Talent (dann ist es wirklich schwierig, Themen zu wechseln, leicht zu entwerfen). Es gibt noch viele Bereiche, die im Projekt optimiert und verbessert werden müssen. Jeder ist herzlich eingeladen, Probleme zu erwähnen (es gibt eine Q -Gruppe am Ende des Artikels, und Sie können gerne gemeinsam lernen und kommunizieren).
Weniger Klatsch spricht dieser Artikel hauptsächlich über den Designprozess des Projekts und einige funktionale Implementierungsideen. Studenten, die sich für das Projekt interessieren, wechseln bitte zum Quellcode Vchat - von Kopf bis Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe Toe, um online zu chatten.
* Dies ist der Teiler.
Das Front-End verwendet hauptsächlich Vue-Familien-Eimer, und es gibt nichts zu sagen, Gerüstkonstruktionsprojekte, Vuex State Management, Vue-Router-Steuerungsrouting und Axios für die Front-End-Interaktion. Das Backend ist ein Dienst, der auf Knoten basiert und Express verwendet. Warum benutze ich KOA nicht? Es dient nur aus Gründen der Bequemlichkeit, denn KOA ist nicht vertraut (bedeckt ihr Gesicht). Das Wichtigste im Chat ist natürlich die Kommunikation. Das Projekt verwendet Socket.io, um vorne und hinten zu kommunizieren.
Die Datenbank ist MongoDB, die hauptsächlich Benutzer, Freunde, Gruppen -Chats, Nachrichten, Ausdrücke, Zahlenpools usw. umfasst.
Funktionsübersicht
Verzeichnisstruktur
// 前端
├─build
├─config
├─src
│ ├─api // 接口api
│ ├─assets // 静态资源
│ │ └─img
│ ├─directives // 全局指令
│ ├─libs // 全局组件
│ │ ├─bscroll
│ │ ├─dropdown
│ │ ├─icon
│ │ ├─nodata
│ │ ├─PhotoSwipe
│ │ ├─uploadPopover
│ │ └─vScroll
│ ├─router // 路由
│ ├─store // 状态管理
│ ├─utils // 方法
│ └─views
│ ├─applicationModel
│ │ ├─games // 游戏
│ │ │
│ │ └─sub // 应用
│ ├─components // 组件
│ │ ├─APlayer
│ │ ├─chat
│ │ ├─cropper
│ │ ├─DPlayer
│ │ └─header
│ ├─personalModel // 主页
│ │ ├─appModel // 天气等
│ │ ├─friendModel // 好友
│ │ └─groupModel // 群聊
│ └─settingModel // 设置
└─static
├─css // 样式文件
├─font // 字体文件
└─theme // 主题
└─vchatWenn ein Benutzer in VCHAT registriert, wird zufällig eine Codenummer angegeben, und diese Codenummer wird aus einem vorgenerierten Zahlenpool übernommen (der Zahlenpool ist in MongoDB vorhanden). Das als 10000001-10001999 angegebene anfängliche Zahlensegment ist der Benutzercode, und das Zahlensegment von 100001-100999 ist der Gruppenchatcode. Benutzer können sich mit ihrer Codenummer oder ihrem Konto anmelden.
// 号码池设计
* code 号码
* status 1 已使用 0 未使用
* type 1 用户 2 群聊
* random 随机数索引,用于随机查找某一条
// user表主要字段
* name 账号
* pass 密码
* avatar 头像
* signature 个性签名
* nickname 昵称
* email 邮件
* phone 手机
* sex 性别
* bubble 气泡
* projectTheme 项目主题
* wallpaper 聊天壁纸
* signUpTime 注册时间
* lastLoginTime 最后一次登录时间
* chatColor 聊天文字颜色
* province 省
* city 市
* town 县
* conversationsList 会话列表
* cover 封面列表Bei der Registrierung müssen Sie feststellen, ob das Konto bereits vorhanden ist, und der zufällig erhaltene Code muss als im Nummernpool verwendet werden, und das Benutzerkennwort wird mit MD5 usw. verschlüsselt.
// md5 密码加密
const md5 = pass => { // 避免多次调用MD5报错
let md5 = crypto . createHash ( 'md5' ) ;
return md5 . update ( pass ) . digest ( "hex" ) ;
} ;Login muss auch feststellen, ob sich der Benutzer registriert hat und das Konto und Code unterstützt, um sich anzumelden.
const login = ( params , callback ) => { // 登录
baseList . users
. find ( { // mongodb中可以直接用$or表示或关系
$or : [ { "name" : params . name } , { "code" : params . name } ]
} )
. then ( r => {
if ( r . length ) {
let pass = md5 ( params . pass ) ;
if ( r [ 0 ] [ 'pass' ] === pass ) {
//更新最后一次登录时间 此处直接写Date.now 会报错 需要Date.now()!!!;
baseList . users . update ( { name : params . name } , { lastLoginTime : Date . now ( ) } ) . then ( raw => {
console . log ( raw ) ;
} ) ;
callback ( { code : 0 , data : { name : r [ 0 ] . name , photo : r [ 0 ] . photo } } ) ;
} else {
callback ( { code : - 1 } ) ;
}
} else {
callback ( { code : - 1 } ) ;
}
} )
} ;Login Berechtigungsverwaltung
app . use ( '/v*' , ( req , res , next ) => {
if ( req . session . login ) {
next ( ) ;
} else {
if ( req . originalUrl === '/v/user/login' || req . originalUrl === '/v/user/signUp' ) {
next ( ) ;
} else {
res . json ( {
status : 0
} ) ;
}
}
} ) ; // http response 服务器响应拦截器,这里拦截未登录和401错误,并重新跳入登页重新获取token
instance . interceptors . response . use (
response => { // 拦截未登录
if ( response . data . status === 0 ) {
router . replace ( '/' ) ;
}
return response ;
} ,
error => {
if ( error . response ) {
switch ( error . response . status ) {
case 401 :
// 这里写清除token的代码
router . replace ( '/' ) ;
}
}
return Promise . reject ( error . response . data )
} ) ;In Vchat umfassen die Arten von Nachrichten Freunde oder Gruppenanwendung, Antwortanwendung (Zustimmung oder Ablehnung), Benachrichtigung über Gruppeneintrag, Chat -Nachricht (Text, Bilder, Ausdrücke, Dateien).
Bevor Sie das Senden von Nachrichten implementieren, müssen Sie ein allgemeines Verständnis für eine
socket.io-APIs haben. Für eine detaillierte API -Dokumentation können Sie Socket.io anzeigen
// 所有的消息请求都是建立在已连接的基础上的
io . on ( 'connect' , onConnect ) ;
// 发送给当前客户端
socket . emit ( 'hello' , 'can you hear me?' , 1 , 2 , 'abc' ) ;
// 发送给所有客户端,除了发送者
socket . broadcast . emit ( 'broadcast' , 'hello friends!' ) ;
// 发送给同在 'game' 房间的所有客户端,除了发送者
socket . to ( 'game' ) . emit ( 'nice game' , "let's play a game" ) ;
// 发送给同在 'game' 房间的所有客户端,包括发送者
io . in ( 'game' ) . emit ( 'big-announcement' , 'the game will start soon' ) ;Schließen Sie sich dem Raum in der Sitzungsliste an. Die Sitzungsliste wird automatisch hinzugefügt, wenn die Freundschaftsanwendung erfolgreich ist oder die Gruppe erfolgreich hinzugefügt wird. Sie können aber auch manuell entfernen oder hinzufügen und keine Nachrichten über die entfernte Sitzung mehr erhalten (ähnlich wie das Blockieren).
// 前端 发起加入房间的请求
this . conversationsList . forEach ( v => {
let val = {
name : this . user . name ,
time : utils . formatTime ( new Date ( ) ) ,
avatar : this . user . photo ,
roomid : v . id
} ;
this . $socket . emit ( 'join' , val ) ;
} ) ;
// 后端 接受请求后执行加入操作,记录每个房间加入的成员,以及回信告知指定房间已上线成员
socket . on ( 'join' , ( val ) => {
socket . join ( val . roomid , ( ) => {
if ( OnlineUser [ val . name ] ) {
return ;
}
OnlineUser [ val . name ] = socket . id ;
io . in ( val . roomid ) . emit ( 'joined' , OnlineUser ) ; // 包括发送者
} ) ;
} ) ;Gleichzeitig wird ein Problem mit dem Beitritt zu mehreren Chatrooms bestehen. Der Sockel kann mehrere Räume beitreten und Nachrichten an die angegebenen Räume senden, unterscheidet jedoch nicht die Räume beim Annehmen von Nachrichten. Mit anderen Worten, alle Nachrichten aus dem Raum werden gemeinsam an den Kunden gesendet. Wir müssen also unterscheiden, welche Botschaft aus welchem Raum stammt und sie verteilen kann. Dies erfordert eine Raumkennung, um zu filtern, und Vchat verwendet die Raum -ID.
mes ( r ) { // 只有本房间的消息才展示
if ( r . roomid === this . currSation . id ) {
this . chatList . push ( Object . assign ( { } , r , { type : 'other' } ) ) ;
}
} // 前端
send(params, type = 'mess') { // 发送消息
if (!this.message && !params) {
return;
}
let val = {
name: this.user.name,
mes: this.message,
time: utils.formatTime(new Date()),
avatar: this.user.photo,
nickname: this.user.nickname,
read: [this.user.name],
roomid: this.currSation.id,
style: 'mess',
userM: this.user.id
};
this.chatList.push(Object.assign({},val,{type: 'mine'})); // 更新视图
this.$socket.emit('mes', val);
this.message = '';
}
// 后端 接收消息后存储到数据库,并转发给房间内其他成员,不包括发送者。
socket.on('mes', (val) => { // 聊天消息
apiList.saveMessage(val);
socket.to(val.roomid).emit('mes', val);
});
Alle Nachrichten werden in MongoDB gespeichert. Beim Umschalten von Räumen werden historische Nachrichten erhalten. Im aktuellen Raum werden die neuesten Nachrichten nur an die DOM beigefügt und werden nicht aus der Datenbank abgerufen. Das Chat -Fenster zeigt nur die neuesten 100 Nachrichten standardmäßig an, und im Chat -Verlauf können weitere Nachrichten angezeigt werden.
// 前端 获取指定房间的历史消息
this . $socket . emit ( 'getHistoryMessages' , { roomid : v . id , offset : 1 , limit : 100 } ) ;
// 后端 关联表、分页、排序
messages . find ( { roomid : params . roomid } )
. populate ( { path : 'userM' , select : 'signature photo nickname' } ) // 关联用户基本信息
. sort ( { 'time' : - 1 } )
. skip ( ( params . offset - 1 ) * params . limit )
. limit ( params . limit )
. then ( r => {
r . forEach ( v => { // 防止用户修改资料后,信息未更新
if ( v . userM ) {
v . nickname = v . userM . nickname ;
v . photo = v . userM . photo ;
v . signature = v . userM . signature ;
}
} ) ;
r . reverse ( ) ;
callback ( { code : 0 , data : r , count : count } ) ;
} ) . catch ( err => {
console . log ( err ) ;
callback ( { code : - 1 } ) ;
} ) ;Startseite
Das Chat -Fenster kann gezogen oder zoomen, Chat -Wallpaper und Textfarbeneinstellungen gezogen werden.
Persönliche Einstellungen
Anwendungsraum
In diesem Artikel geht es hauptsächlich um das Gesamtdesign von VCHAT und die Implementierung einiger Hauptfunktionen. Tatsächlich gibt es immer noch viele Fallstricke beim Schreiben von Projekten wie Mongoose-Inter-Tisch-Abfrage, Datei-Upload usw. Ich werde hier nicht in Details eingehen, und ich werde sie aktualisieren, wenn ich in Zukunft Zeit habe. Wenn Vchat für Sie hilfreich ist, denken Sie daran, ^_ ^zu starren.