当前位置: 首页 > 后端技术 > Node.js

react+react-router+redux+Node.js+socket.io写一个聊天webapp

时间:2023-04-03 16:42:13 Node.js

1.项目预览之前看了一个写聊天的教程,自己跟着教程,因为懒得做找图片和一些我会用教程里的素材做图标,主要用到react+react-router+redux+Node.js+socket.io的技术栈,接下来就是项目预览1.首先可以看到/login下有登录和注册按钮2.点击注册按钮,路由跳转到/register,注册一个账号,用户和密码都是LHH,选择“genius”,点击register,然后路由会跳转到/geniusinfo,这是天才的完美信息页面,选择一个头像并完成信息点击保存按钮3.可以看到已经进入了内容页面,有三个tab选项。点击“我”,路由会跳转到/me可以看到个人中心的内容,但是此时老板和消息的标签页还是没有内容。您可以按照前面的步骤注册一个老板账号。注册时选择老板选项即可。4、现在可以分别在LHH和LCE账户中看到列表了。,然后解释一下项目的主要内容1.去掉node_modules后项目的目录├─build│└─static│├─css│└─js├─config│└─jest├─public├─scripts├─server└─src├─组件│├─authroute│├─头像选择器│├─boss│├─chat│├─dashboard│├─genius│├─img│├─logo│├─msg│navlink│└─img│├─user│└─usercard├─container│├─bossinfo│├─geniusinfo│├─login│└─register└─reduxbuild文件夹里面的内容就是npmrunbuild的打包内容。如果项目中启用了后端接口,也可以访问2.入口页面importReactfrom'react';进口tReactDOMfrom'react-dom';import{createStore,applyMiddleware,compose}from'redux';importthunkfrom'redux-thunk';import{Provider}from'react-redux';//eslint-disable-next-lineimport{BrowserRouter}from'react-router-dom';从'./app'导入应用程序从'./reducer'导入reducers导入'./config'导入'./index.css'conststore=createStore(reducers,compose(applyMiddleware(thunk),window.devToolsExtension?window.devToolsExtension():f=>f))//老板天才我msg4页ReactDOM.render((),document.getElementById('root'))使用react-redux的Provider可以实现全局状态存储,子组件可以通过propsstore=createStore(reducers,compose(applyMiddleware(thunk),window.devToolsExtension?window.devToolsExtension():f=>f))上面代码的主要作用是配置浏览器的redux插件,通过这个插件可以控制查看台中状态下的数据来看下app.js中的代码importReactfrom'react'importLoginfrom'./container/login/login.js';importRegisterfrom'./container/register/register.js';importAuthRoutefrom'./component/authroute/authroute.js';从'./container/bossinfo/bossinfo.js'导入BossInfo;从'./container/geniusinfo/geniusinfo'导入Geniusinfo;从'./component/dashboard/dashboard'导入仪表板;从'./component/chat/chat'导入聊天从'react-router-dom'导入{Route,Switch};classAppextendsReact.Component{render(){return(

)}}在此处导出默认应用程序主要是把主页里面的代码分开了。在authroute.js中,就是路由跳转的逻辑判断。页面中的UI组件同样使用了antd-mobile插件。客户端接收和发送数据,必须导入socket.io-client。代码在chat.redux.js中。聊天中需要存入数据库的内容主要是from(sender),to(receiver),read(读与否),content(聊天内容),create_time(聊天时间)还需要一个唯一的chatid来代表这个聊天室的唯一性,可以用from和to进行拼接,拼接功能是在util.js中写的。3、服务器后台接口使用node.js的express框架,数据库使用mongodb,连接数据库的文件存放在server文件夹中。Model.js直接连接到mongodb数据库。constmongoose=require('mongoose');//连接到mongo,并使用集合my_appconstDB_URL="mongodb://localhost:27017/chat_app";mongoose.connect(DB_URL);constmodels={user:{'user':{'type':String,'require':true},'pwd':{'type':String,'require':true},'type':{'type':String,'require':true},//头像'avatar':{'type':String},//个人简介或工作简介'desc':{'type':String},//职位名称'title':{'type':String},//如果是老板,还有两个字段'company':{'type':String},'money':{'type':String}},chat:{'chatid':{'type':String,'require':true},'from':{'type':String,'rewuire':true},'to':{'type':String,'require':true},'read':{'type':String,'require':true},'content':{'type':String,'require':true,'default':''},'create_time':{'type':Number,'default':newDate().getTime()}}}for(letminmodels){mongoose.model(m,newmongoose.Schema(models[m]))}module.exports={getModel:function(name){returnmongoose.model(name)}}连接的数据库端口号为27017,具体取决于你电脑的数据库端口号在server.js中引入了http、express、socket.io插件,服务端使用的是9093端口,constexpress=require('express');constbodyParser=require('body-parser');constcookieParser=require('cookie-parser');constmodel=require('./model')//constUser=model.getModel('user');constChat=model.getModel('chat');constpath=require('path')constapp=express();//使用expressconstserver=require('http').Server(app);constio=require('socket.io')(server);io.on('connection',function(socket){//console.log('userlogin')socket.on('sendmsg',function(data){const{from,to,msg}=data;constchatid=[from,to].sort().join('_');Chat.create({chatid,from,to,content:msg},function(err,doc){//console.log(doc._doc)io.emit('recvmsg',Object.assign({},doc._doc))})//console.log(data);//io.emit('recvmsg',data)})})constuserRouter=require('./用户');app.use(cookieParser());app.use(bodyParser.json())app.use('/user',userRouter);app.use(function(req,res,next){if(req.url.startsWith('/user/')||req.url.startsWith('/static/')){returnnext()}returnres.sendFile(path.resolve('build/index.html'))})app.use('/',express.static(path.resolve('build')))server.listen(9093,function(){console.log('Nodeappstartatport9093')});客户端编写的接口在user.js中constexpress=require('express')constRouter=express.Router();constmodel=require('./model')constUser=model.getModel('user');constChat=model.getModel('chat');const_filter={'pwd':0,'__v':0};//删除所有聊天记录//Chat.remove({},function(e,d){})//加密constutils=require('utility');Router.get('/list',function(req,res){const{type}=req.query//删除所有用户//User.remove({},function(e,d){})User.find({type},_filter,function(err,doc){returnres.json({code:0,data:doc})})});Router.get('/getmsglist',function(req,res){constuser=req.cookies.userid;User.find({},function(err,userdoc){letusers={};userdoc.forEach(v=>{users[v._id]={name:v.user,avatar:v.avatar}})Chat.find({'$or':[{from:user},{to:user}]},function(err,doc){//console.log(doc)if(!err){returnres.json({code:0,msgs:doc,users:users})}})})})Router.post('/readmsg',function(req,res){constuserid=req.cookies.userid;const{from}=req.body;//console.log(userid,from)Chat.update({from,to:userid},{'$set':{read:true}},{'multi':true},function(err,doc){if(!err){returnres.json({code:0,num:doc.nModified})}returnres.json({code:1,msg:'修改失败'})})})Router.post('/update',function(req,res){constuserid=req.cookies.u塞里德;if(!userid){returnjson.dumps({code:1});}constbody=req.body;User.findByIdAndUpdate(userid,body,function(err,doc){constdata=Object.assign({},{user:doc.user,type:doc.type},body)returnres.json({code:0,数据})})});Router.post('/login',function(req,res){const{user,pwd}=req.body;User.findOne({user,pwd:md5Pwd(pwd)},_filter,function(err,doc){if(!doc){returnres.json({code:1,msg:'用户名或密码错误'});}res.cookie('userid',doc._id)returnres.json({code:0,data:doc})})});Router.post('/register',function(req,res){console.log(req.body);const{user,pwd,type}=req.body;User.findOne({user},function(err,doc){if(doc){returnres.json({code:1,msg:'用户名重置'})}constuserModel=newUser({user,pwd:md5Pwd(pwd),type});userModel.save(function(e,d){if(e){returnres.json({code:1,msg:'backenderror'})}const{user,type,_id}=d;res.cookie('userid',_id)returnres.json({code:0,data:{user,type,_id}})})})})Router.get('/info',function(req,res){const{userid}=req.cookies;if(!userid){returnres.json({code:1})}User.findOne({_id:userid},_filter,function(err,doc){if(err){returnres.json({code:1,msg:'Errorinbackend'})}if(doc){returnres.json({code:0,data:doc})}})//用户没有cookie});//密码盐函数md5Pwd(pwd){constsalt='lhh_is_good_1310486!@#5^%~*';returnutils.md5(utils.md5(pwd+salt))}module.exports=Router3.总结本项目实现了数据获取和性能的代码分离,也是对学习React、Node、WebSocket的进一步提升。当然还有很多可以改进的地方,比如用async和await的异步数据获取等wait作为一个前端菜鸟,还是希望前辈们能给点学习的建议和指点。最后附上本项目github链接的代码链接