vue+express+websocket+mongodb在线群聊工具

vue+express+websocket+mongodb在线群聊工具

1.项目概述

本项目是一个在线群聊工具,前端由vue搭建,后端采用express搭建,前后端通信采用ajax,使用vuex状态管理,能够使用websocket技术实现群发功能,用户和群聊的群信息存储于mongodb数据库中。
项目运行效果图如下:

2.项目运行

环境配置
需安装mongodb
建议安装mongodb Compass可视化管理数据库
需安装nodeJS环境,安装vue和express,以及运行时需要的各种组件
运行
1.启动mongdb服务

mongod
mongo

2.运行服务端

cd chatServer
npm start

3.运行客户端

cd chatClient
npm run dev

项目结构

3.项目代码细节

3.1 后端

3.1.1 nodejs连接数据库

创建db.js 负责数据库连接的初始化

当前文件夹下,安装mongoose包

npm install mongoose
  1. 连接数据库

在命令行已经启动了数据库的情况下,nodejs环境下按如下代码使用mongoose访问数据库

const mongoose = require('mongoose')
// 									 /数据库名
mongoose.connect('mongodb://localhost/firstDatabase', { useUnifiedTopology: true, useNewUrlParser: true}) // mongoose包下connect() 返回Promise对象
    .then(function() {
        console.log('数据库连接成功');
    })
    .catch(function() {
        console.log('数据库连接失败');
    })
  1. 设计document结构(表结构)
...
const UserSchema = new Schema({
    id: {type: Number},         // 用户账号
    name: {type: String},       // 用户昵称
    pwd: {type: Number},        // 密码
    regTime: {type: Number}     // 注册时间
})
....
  1. 将文档结构发布为模型
// 返回值是模型构造函数
const db={
    UserModel: mongoose.model('UserModel',UserSchema),
    GroupModel: mongoose.model('GroupModel',GroupSchema),
    Record1Model: mongoose.model('Record1Model',RecordSchema),
    Record2Model: mongoose.model('Record2Model',RecordSchema)
}
  1. 有了模型构造函数之后,就可以对document(表)进行增删改查
...
const initUser=[
    {
        'id': 100,
        'name': '张三',
        'pwd': 100,
        'regTime': 1111111112222222
    },
    {
        'id': 101,
        'name': '李四',
        'pwd': 101,
        'regTime': 1111111112222223
    }
]
...
//使用模型构造函数(db.UserModel、db.GroupModel、db.Record1Model、db.Record2Model),进行表操作
const initData = function (){
    /**
     * 初始化UserModel表
     * find 查询
     *  第一个参数:查询条件
     *  最后一个参数:回调函数,查询结果会通过回调函数返回,如果不传回调函数,压根不会查询。*/
    db.UserModel.find({},(err,doc)=>{
        if(err){
            console.log('User  用户的初始化出错'+err);
        }else if(!doc.length){
            console.log('User表第一次打开');
            // 初始化User,遍历插入
            initUser.map(item=>{
                db.UserModel.create(item);
            })
        }else{
            console.log('User表已初始化');
        }
    })
}
...
 module.exports=db
3.1.2 创建api.js负责数据库操作

app.js是初始运行文件,在其中配置

var apiRouter=require('./routes/api');
app.use('/api',apiRouter);

api.js

var express = require('express');
var router = express.Router();

// 连接数据库并初始化
const db=require('../db')
const {modelNames} = require("mongoose");

// 登录
router.get('/login', function(req, res) {...});

// 注册
router.get('/register',function (req,res){...});

//获取群信息
router.get('/getGroup',function (req,res) {...})


module.exports = router;

3.2 前端

3.2.1 前端功能简述

login.vue

登录/注册,判断登录/注册的合法性(与后端api的交互),成功则更新当前用户在在线状态 chatState,跳转到control页面

control.vue

获取当前的用户状态,获取该用户的群信息(与后端api的交互)

展示群信息,点击其中一个群后,更新当前群状态 groupState,跳转到chat页面 把点击的当前群信息带上

chat.vue

获取当前用户状态,群状态

用群状态获取当前群成员信息

用群状态获取当前聊天记录(与后端api的交互)

发送消息

3.2.2 前端通过axios访问后端数据
<span class="top-name">{{groupName}}</span>
getGroups () {
      this.$axios({
        url: 'http://192.168.43.190:3000/api/getGroup',
        method: 'GET'
      })
        .then((res) => {
          let data = res.data
          if (data.code === 200) {
            // 从返回数据中获取群信息
            this.Groups = data.Groups
            console.log(data.msg)
          } else {
            // 获取失败
            console.log(data.msg)
          }
        })
    },

3.2 通过Vuex实现状态管理

新建文件夹vuex,创建store.js

初始化store.js的内容

import Vue from 'vue'
import Vuex from 'vuex'
// 挂载VueX
Vue.use(Vuex)
// 创建VueX对象
export default new Vuex.Store({
  state: {
    // 存放的键值对就是所要管理的状态
    // name: 'helloVueX' // 文档的test
    chatState: {
      id: null,
      name: null
    },
    groupState: null
  },
  /**
   * mutations 是对state成员状态的写方法
   * mutations方法的调用方式为this.$store.commit(‘method’,[payload])
   */
  mutations: {
    // 参数的传递?
    updateChatState (state, obj) {
      state.chatState = obj
    },
    updateGroupState: function (state, obj) {
      state.groupState = obj
    }
  },
  /**
   * getters 读取state成员状态并进行加工给外界的方法
   * 只读取的例如this.$store.state.name
   * getters方法的调用方式为this.$store.getters.method()
   */
  getters: {
    getChatState (state) {
      return state.chatState
    },
    getGroupState (state) {
      return state.groupState
    }
  },
  /**
   * actions 用于异步操作,一般是用来和后端同步状态
   * 由于直接在mutation方法中进行异步操作,将会引起数据失效,所以提供了Actions来专门进行异步操作
   * 其中需要通过context.commit(‘method’,[payload])调用mutation方法
   * actions方法的调用方式this.$store.dispatch(‘method’,[,payload])
   * */
  // updateChatState (context, status) {
  //   context.commit('updateChatState', status)
  // }
  // es6解构写法
  actions: {
    updateChatState ({commit}, obj) {
      console.log('updateChatState', obj)
      commit('updateChatState', obj)
    },
    updateGroupState ({commit}, obj) {
      console.log('updateGroupState', obj)
      commit('updateGroupState', obj)
    }
  }
})

将创建的VueX对象Store挂载到当前项目的Vue实例中去

打开main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './vuex/store' // VueX

Vue.config.productionTip = false

/* eslint-disable no-new */
// 将store挂载到当前项目的Vue实例当中去
new Vue({
  el: '#app',
  router,
  store, // VueX
  components: { App },
  template: '<App/>'
})

在组件中使用vuex

例如在App.vue中,我们要将state中定义的name拿来在h1标签中显示

<template>    
	<div id='app'>        
        name:        
        <h1>{{ $store.state.name }}</h1>    
    </div>
</template>

或者要在组件方法中使用

...,
methods:{    
	add(){      
		console.log(this.$store.state.name)    
	}
},
...

3.3 通过websocket实现群发消息

  1. 连接websocket
this.socket = io.connect('http://localhost:8081')
  1. 组织数据
// 组织数据
let chat = {
    id: this.$store.getters.getChatState.id,
    name: this.$store.getters.getChatState.name,
    chatTime: Date.parse(new Date()),
    chatMes: this.editText,
    chatGroup: this.groupState.groupId,
    chatType: 'chat'
}
  1. 在线发送消息
this.socket.emit('emitChat', chat)
  1. 客户端监听服务端
this.socket.removeAllListeners()
let that = this
this.socket.on('emitChat', function (data) {
    console.log('收到emitChat')
    let chat = data
    chat.chatTime = that.timeFormat(chat.chatTime)
    that.chatLog.push(chat)
})
  1. 服务端监听客户端
// 监听emitChat
  socket.on('emitChat',function (data) {
    console.log('服务端监听到emitChat')
    chat=data
    console.log(data)
    // 向所有连上socket的广播emitChat消息
    io.emit('emitChat',chat)
  })

4.遇到的问题及解决

4.1 箭头函数

<script>
import axios from 'axios'

export default {
  data () {
    return {
      msg: 'default msg'
    }
  },
  created () {
    this.msg = 'change'
    axios
      .get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then((response) => {
        // 处理成功情况
        console.log('前端通过axios访问后端成功')
        this.msg = response
        // 将HTTP响应的结果显示到页面上
        document.getElementById('content').innerHTML = response
      })
      .catch((error) => {
        // 处理错误情况
        console.log('前端通过axios访问后端失败' + error)
      })
  }
}

注意,箭头函数不是简单的function(){}匿名函数的简写,实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,再编写函数时就已经确定了。而匿名函数this指向运行时实际调用该方法的对象,无法在编写函数时确定。

所以下述写法中的this会出错!!!

created () {
    this.msg = 'change'
    axios
      .get('https://api.coindesk.com/v1/bpi/currentprice.json')
      .then(function (response){
        console.log('前端通过axios访问后端成功')
        this.msg = response
        document.getElementById('content').innerHTML = response
      })
      .catch(function (error){
        console.log('前端通过axios访问后端失败' + error)
      })
  }

[(img-A0SUpAz3-1642146658953)(C:\Users\butterFly\AppData\Roaming\Typora\typora-user-images\image-20211208143142712.png)]

4.2 cors跨域问题

cros跨域

express后端项目中安装cors

cnpm install cors --save

在app.js文件中引入cors,写下如下几行代码

var cors=require('cors');
app.use(cors({
    origin:['http://localhost:8080'],  //指定接收的地址
    methods:['GET','POST'],  //指定接收的请求类型
    alloweHeaders:['Content-Type','Authorization']  //指定header
}))

4.3 编程式页面跳转

router.push({ path: 'chat' }) //出现url改变,但页面不刷新的问题
//改为
this.$router.push({ path: 'chat' })

4.4 不推荐使用对象作为key

不推荐使用对象作为key
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue是一种流行的JavaScript框架,用于构建单页面应用程序(SPA)。Spring Boot是一种Java框架,用于构建Web应用程序。 Spring Security是Spring框架的安全性模块,用于提供身份验证和授权功能。WebSocket是一种协议,用于在Web应用程序中实现双向通信。Token则是在用户验证过程中传输的一种凭证。 Vue和Spring Boot的流行度,使得它们是构建现代Web应用程序的理想选择。当应用程序需要安全性和实时性时,Spring Security和WebSocket技术是最佳的选择。在Spring Boot中,使用Spring Security模块可以轻松地添加身份验证,并对请求进行基于角色的访问控制。此外,Spring Security还提供了多种身份验证方案,如基础身份验证和JWT身份验证。 对于实时性,WebSocket提供了一种优雅的解决方案。在Web应用程序中,传统的HTTP请求是一种单向通信模式,即客户端发起请求,服务器响应请求。WebSocket协议通过建立持久连接,允许双向通信。这意味着服务器可以在没有客户端请求的情况下向客户端发送数据,从而实现实时更新。这尤其适用于聊天和数据可视化应用程序。 当使用Vue和Spring Boot构建实时应用时,可以使用WebSocketVuevue-socket.io插件轻松地实现数据传输。Vue-socket.io插件允许将socket.io集成到Vue组件中,以便在应用程序中使用。 当应用程序需要安全性时,可以使用Spring Security的JWT身份验证方案。这需要在服务器端创建一个JWT令牌,并将其发送到客户端。客户端在发送后每次请求时都要将这个令牌包含在请求中。服务器将验证这个令牌,并使用已经验证的用户身份对请求进行授权。 总之,Vue,Spring Boot,Spring Security和WebSocket的结合可以为Web应用程序的安全性和实时性提供完美的解决方案。使用JWT身份验证和Vue-socket.io插件,可以轻松地实现这些功能。无论是聊天应用程序还是数据可视化应用程序,这些技术都可以提高应用程序的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值