阿里云优惠活动,点击链接进行购买: 一年仅需96.9元即可以购买服务器~
腾讯云优惠活动, 点击链接进行购买一年仅需99元
腾讯云限时开团活动, 点击链接进行购买一年仅需95元
在原来基础上增加了多个聊天室以及发送图片【vue+websocket+express+mongodb 实战项目(实时聊天)(二)】 http://blog.csdn.net/blueblueskyhua/article/details/73250992 旧版聊天室地址: https://github.com/hua1995116/webchat/tree/08ff845a2ca46c27a9024138d5b4173c89dd8056 新版地址: https://github.com/hua1995116/webchat ————————————————————————————— 继上一个项目用 vuejs 仿网易云音乐(实现听歌以及搜索功能) (opens new window)后,发现上一个项目单纯用 vue 的 model 管理十分混乱,然后我去看了看 vuex,打算做一个项目练练手,又不想做一个重复的项目,这次我就放弃颜值,打算走心派。结合了后台 nodejs,以及数据库 mongodb 来开发了一个实时聊天系统。这个系统可以说是一统江山,也算是实现前端程序员的一个梦了,前后通吃。自认为是一个比全的项目。项目地址:https://github.com/hua1995116/webchat (opens new window) 觉得好的请顺手来个 star。
技术栈
结构
├─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 (opens new window)。其余都是脚手架的默认配置。
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 } ] })
大家可以看到一共有三个路由,没错,我们就是写了三块,第一块是和大家一起的聊天室,第二块是和我们可爱的大白聊天,也就是我们的图灵机器人 (opens new window)。有空你也去搞一个耍耍。第三块就是我们的个人中心,虽然这一块没什么东西。但是毕竟好看,哦~忘了,我们是走心的,怎么可以只看脸。
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 (opens new window)。有了这个就可以和服务端进行交互。等会讲解服务端。
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/ (opens new window)
服务器端
由于 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 (opens new window)
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 (opens new window) 在线观看地址:http://www.qiufengh.com:8081/#/ (opens new window)
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改成自己的项目地址。
最后上几张图。