더 이상 유지되지 않습니다
이 프로젝트는 내가 공부할 때 작성되었으며 일부 장소는 읽기 쉽지 않습니다 (예 : 몽고 부분의 많은 콜백과 같은). 그것을 필요로하는 학생들은주의 깊게 읽으십시오. 감사합니다.
지점 코드는 온라인 상태이며 그에 따라 변경되었습니다. 기본적으로 채팅 그룹에 가입하고 백엔드가 일부 Linux 코드 조정에 적응할 수있는 경우 마스터를 당기는 것이 좋습니다.
노드, NPM 및 MongoDB가 있어야합니다. 프로젝트의 기본 MongoDB IP 주소는 127.0.0.1:27017로 구성 파일에서 수정할 수 있습니다. (chatserver utils database.js)
cd chatRoom
npm install 安装前端依赖
npm run build 编译前端代码
cd ..
cd chatServer
npm install 安装后端依赖
npm run create 初始化数据库(号码池、表情包)
npm start 启动服务
在浏览器中打开 localhost:9988 即可
이 프로젝트는 작업에 대화방 기능이 필요했기 때문에 시작했지만 몇 가지 이유로 마침내 XMPP 프로토콜을 기반으로 Strophe.js를 선택했습니다. 그래서 나는 노드를 사용하여 직접 세트를 작성하고 싶었습니다. 나는 원래 채팅 페이지를 작성하고 싶었지만 글을 쓰고 나서 만족하지 못했기 때문에 계속 리팩토링을 계속했습니다 (제품 관리자가 항상 요구 사항을 변경 한 이유를 이해할 수있는 것 같습니다).
Mongodb와 같은 많은 것들도 내가 처음으로 사용한 것입니다. 나는 전에 mySQL에만 노출되었습니다. 그래서 나는 동시에 배우고 썼습니다. 나는 여가 시간을 사용하여 몇 달 동안 간헐적으로 글을 썼습니다 (이번에는 V0.9.0 버전에 대해 이야기했으며 프로젝트가 여전히 업데이트되고 있습니다 ...). 여기에는 전체 프론트 엔드 및 백엔드 상호 작용 세트가 포함됩니다. UI는 내 자신의 감정에서 비롯되며 디자인 재능이 없습니다 (그런 다음 테마를 전환 할 때 디자인하기가 정말 어렵습니다 ~). 프로젝트에서 최적화되고 개선되어야하는 많은 영역이 여전히 있습니다. 모두가 문제를 언급하는 것을 환영합니다 (기사 끝에 Q 그룹이 있으며 함께 배우고 의사 소통 할 수 있습니다).
가십이 적은이 기사는 주로 프로젝트의 설계 프로세스와 일부 기능 구현 아이디어에 대해 이야기합니다. 프로젝트에 관심이있는 학생들은 소스 코드 vchat로 이동하십시오 - 머리부터 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락 발가락은 온라인으로 채팅하십시오.
* This is the divider --------------------------------------------------------------------------------------------------------------------------
프론트 엔드는 주로 VUE 패밀리 버킷을 사용하며, 스캐 폴딩 건설 프로젝트, Vuex State Management, Vue-Router Control 라우팅 및 프론트 엔드 상호 작용을위한 Axios는 할 말이 없습니다. 백엔드는 노드를 기반으로 한 서비스이며 Express를 사용합니다. KOA를 사용하지 않는 이유는 무엇입니까? KOA는 (얼굴을 덮는) 익숙하지 않기 때문에 순전히 편의를위한 것입니다. 채팅에서 가장 중요한 것은 물론 의사 소통입니다. 이 프로젝트는 socket.io를 사용하여 전면 및 백엔드를 통신합니다.
데이터베이스는 주로 사용자, 친구, 그룹 채팅, 메시지, 표현, 번호 풀 등을 포함하는 MongoDB입니다.
기능 개요
디렉토리 구조
// 前端
├─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 // 主题
└─vchat사용자가 VCHAT에 등록하면 코드 번호가 무작위로 지정 되며이 코드 번호는 사전 생성 번호 풀에서 가져옵니다 (번호 풀은 MongoDB에 존재 함). 10000001-10001999로 지정된 초기 숫자 세그먼트는 사용자 코드이고 100001-100999의 숫자 세그먼트는 그룹 채팅 코드입니다. 사용자는 코드 번호 또는 계정으로 로그인 할 수 있습니다.
// 号码池设计
* 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 封面列表등록 할 때 계정이 이미 존재하는지 확인해야하며 무작위로 얻은 코드는 번호 풀에서 사용되는 것으로 표시되어야하며 사용자 비밀번호는 MD5 등으로 암호화됩니다.
// md5 密码加密
const md5 = pass => { // 避免多次调用MD5报错
let md5 = crypto . createHash ( 'md5' ) ;
return md5 . update ( pass ) . digest ( "hex" ) ;
} ;로그인하려면 사용자가 등록했는지 여부를 결정하고 로그인 할 계정 및 코드를 지원해야합니다.
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 } ) ;
}
} )
} ;로그인 권한 관리
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 )
} ) ;VCHAT의 메시지 유형에는 친구 또는 그룹 응용 프로그램, 응답 응용 프로그램 (동의 또는 거부), 그룹 입력 알림, 채팅 메시지 (텍스트, 그림, 표현, 파일)가 포함됩니다.
메시지 보내기를 구현하기 전에
socket.ioAPI에 대한 일반적인 이해가 필요합니다. 자세한 API 문서는 socket.io를 볼 수 있습니다
// 所有的消息请求都是建立在已连接的基础上的
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' ) ;세션 목록의 객실에 가입하십시오. 친구 응용 프로그램이 성공하거나 그룹이 성공적으로 추가되면 세션 목록이 자동으로 추가됩니다. 그러나 수동으로 제거하거나 추가 할 수 있으며 더 이상 제거 된 세션에 대한 메시지를받지 못합니다 (차단과 유사).
// 前端 发起加入房间的请求
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 ) ; // 包括发送者
} ) ;
} ) ;여러 대화방에 동시에 참여하는 데 문제가 있습니다. 소켓은 여러 방에 가입하여 지정된 방에 메시지를 보낼 수 있지만 메시지를 수락 할 때는 방을 구별하지 않습니다. 다시 말해, 객실의 모든 메시지는 클라이언트에게 함께 전송됩니다. 따라서 우리는 어느 방에서 어떤 메시지가 있는지 구별하고 배포해야합니다. 이를 위해서는 객실 식별자가 필터링해야하며 VCHAT는 룸 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);
});
모든 메시지는 MongoDB에 저장됩니다. 방을 전환 할 때 역사적인 메시지가 얻어 질 것입니다. 현재 객실에서 최신 뉴스는 DOM에만 추가되며 데이터베이스에서 검색되지 않습니다. 채팅 창에는 기본적으로 최신 100 개의 메시지 만 표시되며 채팅 기록에서 더 많은 메시지를 볼 수 있습니다.
// 前端 获取指定房间的历史消息
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 } ) ;
} ) ;홈페이지
채팅 창, 드래그 또는 확대, 채팅 배경 화면 및 텍스트 색상 설정이 가능합니다.
개인 설정
응용 프로그램 공간
이 기사는 주로 VCHAT의 전반적인 디자인과 일부 주요 기능의 구현에 대해 이야기합니다. 사실, 몽구스 인터 테이블 쿼리, 파일 업로드 등과 같은 프로젝트를 작성하는 과정에는 여전히 많은 함정이 있습니다. 여기에서 자세히 설명하지 않으면 앞으로 시간이 있으면 업데이트하겠습니다. vchat이 당신에게 도움이된다면 ^_ ^를 응시하는 것을 잊지 마십시오.