• vue+websocket+express+mongodb实战项目(实时聊天)


    博客原文地址:http://www.cnblogs.com/qiufenghua/p/6772949.html,转载请注明出处。

    在原来基础上增加了多个聊天室以及发送图片【vue+websocket+express+MongoDB实战项目(实时聊天)(二)】 
    http://www.cnblogs.com/qiufenghua/p/7018886.html
    旧版聊天室地址: 
    https://github.com/hua1995116/webchat/tree/08ff845a2ca46c27a9024138d5b4173c89dd8056 
    新版地址: 
    https://github.com/hua1995116/webchat 

    ----------------------------------------------------------------------------------------------------------------------------------------------------------

    继上一个项目用vuejs仿网易云音乐(实现听歌以及搜索功能)后,发现上一个项目单纯用vue的model管理十分混乱,然后我去看了看vuex,打算做一个项目练练手,又不想做一个重复的项目,这次我就放弃颜值,打算走心派。结合了后台nodejs,以及数据库MongoDB来开发了一个实时聊天系统。这个系统可以说是一统江山,也算是实现前端程序员的一个梦了,前后通吃。自认为是一个比全的项目。项目地址:https://github.com/hua1995116/webchat 觉得好的请顺手来个star。

    技术栈

    • 前端 vue,vue-router ,vuex
    • 后端 nodejs,express
    • 数据库 mongodb
    • 通讯 websocket
    • 脚手架工具 vue-cli

    结构 
    ├─build 
    ├─config 
    ├─models(存放mongoose对象) 
    ├─schemas(存放mongoose的schemas模型) 
    ├─src 
    │ │ App.vue 
    │ │ main.js(主入口) 
    │ ├─assets 
    │ ├─components (组件) 
    │ ├─router(vue-router路由) 
    │ └─store(vuex) 
    └─static(静态资源)

    首先用脚手架工具构建一个项目。像这样:

    vue init webpack my-project-name
    

    结构大致是这样的

    好!既然我们是实战项目,我就不多说这些配置问题。不然又跑题了。不然又要被小哥哥小姐姐们打了。

    前端

    首先看src目录下的页面布局。 
    main.js// 主入口

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import store from './store'
    // 使用museui组件
    import MuseUI from 'muse-ui'
    import 'muse-ui/dist/muse-ui.css'
    Vue.use(MuseUI)
    Vue.config.productionTip = false
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      store,
      template: '<App/>',
      components: {App}
    })
    

    我们为了让整个项目看起来漂漂亮亮的,所以选择了muse-ui,别说,这个UI框架是真的漂亮。不信大家可以看muse-ui。其余都是脚手架的默认配置。

    route/router.js

    import Vue from 'vue'
    import Router from 'vue-router'
    import Index from '@/components/Index'
    import Robot from '@/components/Robot'
    import Home from '@/components/Home'
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'Index',
          component: Index
        },
        {
          path: '/robot',
          name: 'Robot',
          component: Robot
        },
        {
          path: '/home',
          name: 'Home',
          component: Home
        }
      ]
    })
    

    大家可以看到一共有三个路由,没错,我们就是写了三块,第一块是和大家一起的聊天室,第二块是和我们可爱的大白聊天,也就是我们的图灵机器人。有空你也去搞一个耍耍。第三块就是我们的个人中心,虽然这一块没什么东西。但是毕竟好看,哦~忘了,我们是走心的,怎么可以只看脸。

    components/Chat.vue

    created() {
        const that = this
        this.socket = io.connect('http://qiufengh.com:8081')
        this.socket.on('message', function(obj) {
            that.$store.commit('addroomdetailinfos', obj)
            window.scrollTo(0, 900000)
        })
        this.socket.on('logout', function (obj) {
            that.$store.commit('setusers', obj)
        })
    },
    
    this.socket = io.connect('http://qiufengh.com:8081')
    

      

    这一句,主要用于连接你当前的服务,到时候下载后面的项目时,记得改成自己的服务以及端口。因为是在Index和Chat都有设置,所以你需要在Index.vue和Chat里的connect都改成你自己的服务。socket.on()用于接受消息。socket.emit() 用于发送消息。不懂的socket.io的看这里socket.io。有了这个就可以和服务端进行交互。等会讲解服务端。

    store/index.js

    state: {
     //存放用户
      user: {
        name: '',
        src: ''
      },
      //存放历史记录
      messhistory: {
        infos: []
      },
      //存放房间信息,为了方便以后做多房间
      roomdetail: {
        id: '',
        users: {},
        infos: []
      },
      //存放机器人开场白
      robotmsg: [{
        message: 'Hi~有什么想知道的可以问我',
        user: 'robot'
      }],
      //聊天页面显示控制
      chattoggle: false,
      //登录页面显示控制
      logintoggle: false,
      //注册页面显示控制
      registertoggle: true,
      //提示框显示控制
      dialog: false,
       //提示框内容
      dialoginfo: ''
    }
    

    由于控制代码太多,所以之后的内容请大家移步,我的github地址。https://github.com/hua1995116/webchat/

    服务器端

    由于build下dev-server.js中webpack代码太多,太杂乱,不易于讲解。主要来看看用于打包后的服务器端。两份代码是一样的。 
    prod.server.js(根目录下)

    var express = require('express');
    var config = require('./config/index');
    var port = process.env.PORT || config.dev.port;
    
    var app = express();
    
    var router = express.Router();
    //用于静态展示入口
    router.get('/',function(req,res,next){
        req.url = './index.html';
        next();
    });
    
    app.use(router);
    
    require('./config/routes')(app)
    /*引入*/
    var mongoose = require('mongoose')
    //日志文件
    var morgan = require('morgan')
    //sesstion 存储
    var bodyParser = require('body-parser')
    var cookieParser = require('cookie-parser')
    var session = require('cookie-session')
    //用于异步回调
    mongoose.Promise = require('bluebird')
    global.db = mongoose.connect("mongodb://localhost:27017/vuechat")
    
    //服务器提交的数据json化
    app.use(bodyParser.json())
    app.use(bodyParser.urlencoded({extended: true}))
    //sesstion 存储
    app.use(cookieParser())
    app.use(session({
      secret: 'vuechat',
      resave: false,
      saveUninitialized: true
    }))
    
    var env = process.env.NODE_ENV || 'development'
    if ('development' === app.get('env')) {
      app.set('showStackError', true)
      app.use(morgan(':method :url :status'))
      app.locals.pretty = true
      mongoose.set('debug', true)
    }
    
    var server = app.listen(port)
    
    //websocket
    // var http = require('http').Server(app);
    var io = require('socket.io')(server);
    var Message = require('./models/message')
    var users = {}
    io.on('connection', function (socket) {
      //监听用户发布聊天内容
      socket.on('message', function (obj) {
        //向所有客户端广播发布的消息
        io.emit('message', obj)
        var mess = {
          username: obj.username,
          src:obj.src,
          msg: obj.msg,
          roomid:'room1'
        }
        var message = new Message(mess)
        //将发送过来的消息进行储存
        message.save(function (err, mess) {
          if (err) {
            console.log(err)
          }
            console.log(mess)
        })
        console.log(obj.username + '说:' + obj.msg)
      })
      socket.on('login',function (obj) {
        users[obj.name] = obj
        //用于监听用户进行聊天室
        io.emit('login', users)
      })
      socket.on('logout',function (name) {
        delete users[name]
        //用户监听用退出聊天室
        io.emit('logout', users)
      })
    })
    
    //声明静态资源地址
    app.use(express.static('./dist'));
    

    schema模型

    schema/user.js

    var mongoose = require('mongoose')
    //用于md5加密
    var bcrypt = require('bcryptjs')
    //加盐数
    var SALT_WORK_FACTOR = 10
    var UserSchema = new mongoose.Schema({
      name: {
        unique: true,
        type: String
      },
      password: String,
      src: String,
      meta: {
        createAt: {
          type: Date,
          default: Date.now()
        },
        updateAt: {
          type: Date,
          default: Date.now()
        }
      }
    });
    //对密码进行加密
    UserSchema.pre('save', function (next) {
      var user = this
      if (this.isNew) {
        this.createAt = this.updateAt = Date.now()
      }
      else {
        this.updateAt = Date.now()
      }
      bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
        if (err) return next(err)
    
        bcrypt.hash(user.password, salt, function (err, hash) {
          if (err) return next(err)
    
          user.password = hash
          next()
        })
      })
    })
    //用于比较密码是否正确
    UserSchema.methods = {
      comparePassword: function (_password, cb) {
        bcrypt.compare(_password, this.password, function (err, isMatch) {
          if (err) return cb(err)
          cb(null, isMatch)
        })
      }
    }
    
    UserSchema.statics = {
      fetch: function (cb) {
        return this
          .find({})
          .sort('meta.updateAt')
          .exec(cb)
      },
      findById: function (id, cb) {
        return this
          .findOne({_id: id})
          .exec(cb)
      }
    }
    
    module.exports = UserSchema
    

    这里主要用到一个md5的模块,可以查看 bcryptjs

    schema/message.js

    var mongoose = require('mongoose')
    //聊天记录模型
    var MessageSchema = new mongoose.Schema({
      username: String,
      src:String,
      msg: String,
      roomid:String,
      time: {
        type: Date,
        default: Date.now()
      }
    })
    //静态方法
    MessageSchema.statics = {
      fetch: function (cb) {
        return this
          .find({})
          .sort('time')
          .exec(cb)
      },
      findById: function (id, cb) {
        return this
          .findOne({_id: id})
          .exec(cb)
      }
    }
    module.exports = MessageSchema
    

    服务器的routes 
    config/routes.js 讲一个注册的把,其他请前往项目查看

    app.post('/user/signup', function (req, res) {
        //获取提交数据
        var _user = req.body
        console.log(_user)
        User.findOne({name: _user.name}, function (err, user) {
          if (err) {
            console.log(err)
          }
          if (user) {
            res.json({
              errno: 1,
              data: '用户名已存在'
            })
          } else {
            var user = new User(_user)
            user.save(function (err, user) {
              if (err) {
                console.log(err)
              }
              res.json({
                errno: 0,
                data: '注册成功'
              })
            })
          }
        })
      })
    

    主要用于验证用户名是否重复。

    核心部分就讲到这里啦,。其他具体的请查看我的github地址(具有详细的注释,不明白的可以提问,需要改进的请各位前辈指出): 
    地址:https://github.com/hua1995116/webchat 
    在线观看地址:http://www.qiufengh.com:8081/#/

    npm install -----安装依赖
    npm run dev -----运行
    npm run build -----打包
    node prod.server.js -----打包后运行
    //记得替换
    Index.vue和Chat.vue下的io.connect('http://qiufengh.com:8081')
    http://qiufengh.com:8081改成自己的项目地址。
    

    最后上几张图。 

  • 相关阅读:
    AngularJS学习之旅
    webbug3.0菜鸟笔记1
    CTF练习(1)这是一张单纯的图片?
    三步删除U深度,老毛桃,大白菜捆绑软件!!
    flex弹性布局学习总结
    C# 播放音乐
    获取文件夹中的所有文件名
    C# 利用委托和事件 传入一个参数进行进行计算并返回结果
    C# 自定义颜色
    检测键盘是否按下指定按键
  • 原文地址:https://www.cnblogs.com/qiufenghua/p/6772949.html
Copyright © 2020-2023  润新知