一、项目简介
本项目基于纯前端(移动端)技术开发一个聊天系统,界面美观大方,采用Nodejs+Vue+ElemenetUI开发实现,主要包含:登录注册,修改个人资料,更改头像,发送消息,单对单聊天等。
二、环境介绍
语言环境:nodejs
数据库:MySQL
应用服务器:nodejs
开发工具:vscode
开发技术:nodejs+vue+elementUI
三、系统展示
四、视频功能展示
基于Vue+nodejs+Element-ui的聊天系统项目
五、前端核心代码展示
- 头部导航功能代码
- 登录注册页居中旋转功能代码
- 登录页代码
欢迎登录
点击跳转到注册页
- 注册页代码
欢迎注册
点击跳转到登录页
- 我的主页代码
{{ list.username }}
修改用户基本信息 退出
- 修改个人信息代码
用户名:
个人简介:
提交
- 聊天框内容代码
{{ list.username }} -
{{ list.username }}
{{ item.content }}
- 好友页代码
-
{{ item.username }}
- router 路由页代码
import Vue from 'vue'import VueRouter from 'vue-router'import HomeView from '@/components/home'import axios from 'axios'import store from '@/store/index'Vue.use(VueRouter)const routes = [ { path: '/', name: 'home', redirect: 'footer', component: HomeView, meta: { isLogn:true } }, { path: '/login', name: 'login', component: () => import('@/views/login/index'), }, { path: '/footer', name: 'footer', redirect: {name:'user'}, component: () => import('@/views/home/footer.vue'), meta: { isLogn:true }, children: [ { path: 'user', name: 'user', component: () => import('@/views/user/index.vue'), meta: { isLogn:true } }, { path: 'mine', name: 'mine', component: () => import('@/views/mine/index.vue'), meta: { isLogn:true } }, ] }, { path: '/chat', name: 'chat', component: () => import('@/views/chat/index.vue'), meta: { isLogn:true } }, { path: '/setMessage', name: 'setMessage', component: () => import('@/views/mine/setMessage.vue'), }]const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes})router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') const islogin = !!token // console.log(token, islogin) var data = '' axios({ url: `/api/my/myuser`, method: "get", headers: { Authorization: localStorage.getItem("token"), }, }).then(({ data }) => { store.commit('userInfo', data.list) if (to.matched.some((item) => item.meta.isLogn)) { if (data.status === 1) { localStorage.removeItem('token') window.location.href = '/login' } else { if (islogin) { next() } else { // 没有跳转至登录 window.location.href = '/login' } } } else { if (islogin && to.path === '/login') { // 跳转至首页 window.location.href = '/' return } next() } }) })export default router
- vuex 页代码
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({ state: { userInfo: [], isRolling: false, }, getters: { isLogin(userInfo) { return !!userInfo.username } }, mutations: { addlogin(state) { state.isRolling = !state.isRolling }, userInfo(state, data) { state.userInfo = data } }, actions: { }, modules: { }})
- package.json 页代码
{ "name": "chat_vue", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build" }, "dependencies": { "axios": "^1.1.3", "core-js": "^3.8.3", "element-ui": "^2.15.12", "vue": "^2.6.14", "vue-router": "^3.5.1", "vuex": "^3.6.2" }, "devDependencies": { "@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-vuex": "~5.0.0", "@vue/cli-service": "~5.0.0", "sass": "^1.32.7", "sass-loader": "^12.0.0", "vue-template-compiler": "^2.6.14" }}
- 移动端代码
const WIDTH = 375//如果是尺寸的设计稿在这里修改const setView = () => { //设置html标签的fontSize document.documentElement.style.fontSize = (100 * document.documentElement.clientWidth / WIDTH) + 'px'}window.onresize = setViewsetView()
- main.js页面代码
import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'import ElementUI from 'element-ui';import 'element-ui/lib/theme-chalk/index.css';import axios from 'axios'import '@/rem/index'Vue.prototype.$axios = axiosVue.use(ElementUI);Vue.config.productionTip = falsenew Vue({ router, store, render: h => h(App)}).$mount('#app')
六、MySQL 数据库创建功能展示
- 用户信息表
- 聊天发布内容表
七、node.js 核心代码
- 根页面
// 导入 express 模块const express = require('express')// 创建 express 的服务器实例const app = express()// 导入 cors 中间件const cors = require('cors')// 将 cors 注册为全局中间件app.use(cors())// 配置解析表单数据的中间件app.use(express.json()) // 解析 json 格式// 注意:这个中间件,只能解析 application/x-www-form-urlencoded 格式的表单数据app.use(express.urlencoded({ extended: false }))// 响应数据的中间件app.use(function (req, res, next) { // status = 0 为成功; status = 1 为失败; 默认将 status 的值设置为 1,方便处理失败的情况 res.cc = function (err, status = 1) { res.send({ // 状态 status, // 状态描述,判断 err 是 错误对象 还是 字符串 message: err instanceof Error ? err.message : err, }) } next()})const joi = require('@hapi/joi')// 错误中间件app.use(function (err, req, res, next) { // 数据验证失败 if (err instanceof joi.ValidationError) return res.cc(err) // 未知错误 res.cc(err)})// 导入配置文件const config = require('./config')// 解析 token 的中间件const expressJWT = require('express-jwt')// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证app.use(expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/api\//] }))// 错误中间件app.use(function (err, req, res, next) { // 捕获身份认证失败的错误 if (err.name === 'UnauthorizedError') return res.cc('身份认证失败!')})// 导入并注册用户路由模块const userRouter = require('./router/user')app.use('/api', userRouter)// 导入并使用用户信息路由模块const userallRouter = require('./router/userall')// 注意:以 /my 开头的接口,都是有权限的接口,需要进行 Token 身份认证app.use('/my', userallRouter)app.listen(0830, function () { console.log('api server running at http://127.0.0.1:0830')})
- 接口页面
不加密
// 导入 express 模块const express = require('express')// 创建路由对象const router = express.Router()const multiparty = require('multiparty')var multer = require('multer')const fs = require("fs");// 导入用户路由处理函数模块const userHandler = require('../router_handler/user')router.post('/reguser',userHandler.reguser)router.post('/login',userHandler.login)router.get('/uploads', userHandler.image)// 单图上传router.post( "/upload", multer({ //设置文件存储路径 dest: "public/image", }).array("file", 1), function (req, res, next) { let files = req.files; let file = files[0]; let fileInfo = {}; let path = "public/image/" + 'image_' + file.originalname; fs.renameSync("./public/image/" + file.filename, path); //获取文件基本信息 fileInfo.type = file.mimetype; fileInfo.name = file.originalname; fileInfo.size = file.size; fileInfo.path = path; res.json({ code: 200, msg: "OK", data: fileInfo, }); console.log(fileInfo.path) });// 将路由对象共享出去module.exports = router
加密:
// 导入 expressconst express = require('express')// 创建路由对象const router = express.Router()// 导入用户路由处理函数模块const userAll = require('../router_handler/userall')// 获取所有用户router.get('/userall',userAll.getUserall)// 获取指定用户router.get('/userid', userAll.getUserid)// 获取当前登录用户router.get('/myuser', userAll.getMyuser)// 发布消息router.post('/publish', userAll.setpublish)// 获取消息router.get('/messages', userAll.getMessage)// 更改用户信息router.post('/setmessages', userAll.setMessage)// 向外共享路由对象module.exports = router
- 接口内容页面
不加密:
const db = require('../db/index')// 导入 bcryptjs 插件(对密码进行加密)const bcrypt = require('bcryptjs')// 导入 path 用来显示图片var path = require('path');// 用这个包来生成 Token 字符串const jwt = require('jsonwebtoken')// 导入全局的配置文件const config = require('../config')// 注册用户的处理函数exports.reguser = (req, res,next) => { // 接收表单数据 const userinfo = req.body // 判断数据是否合法 if (!userinfo.username || !userinfo.password) { return res.send({ status: 1, message: '用户名或密码不能为空!' }) } const sql = `select * from users where username=?` db.query(sql, [userinfo.username], function (err, results) { // 执行 SQL 语句失败 if (err) { return res.send({ status: 1, message: err.message }) } // 用户名被占用 if (results.length > 0) { return res.send({ status: 1, message: '用户名被占用,请更换其他用户名!' }) } // 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串 userinfo.password = bcrypt.hashSync(userinfo.password, 10) const articleInfo = { // 标题、内容、状态、所属的分类Id ...req.body, // 文章封面在服务器端的存放路径 image: 'http://127.0.0.1:830/api/uploads?img=1669116817314_21.jpg', // 账号创建时间 time: new Date(), // 作者的Id user_id: Math.floor(Math.random()*(9999999999-100000)+100000) } // console.log(articleInfo) const sql = 'insert into users set ?' db.query(sql, articleInfo, function (err, results) { // 执行 SQL 语句失败 if (err) return res.send({ status: 1, message: err.message }) // SQL 语句执行成功,但影响行数不为 1 if (results.affectedRows !== 1) { return res.send({ status: 1, message: '注册用户失败,请稍后再试!' }) } // 注册成功 res.send({ status: 0, message: '注册成功!' }) }) })}// 登录的处理函数exports.login = (req, res) => { const userinfo = req.body const sql = `select * from users where username=?` db.query(sql, userinfo.username, function (err, results) { // 执行 SQL 语句失败 if (err) return res.cc(err) // 执行 SQL 语句成功,但是查询到数据条数不等于 1 if (results.length !== 1) return res.cc('登录失败!') // TODO:判断用户输入的登录密码是否和数据库中的密码一致 // 拿着用户输入的密码,和数据库中存储的密码进行对比 const compareResult = bcrypt.compareSync(userinfo.password, results[0].password) // 如果对比的结果等于 false, 则证明用户输入的密码错误 if (!compareResult) { return res.cc('登录失败!') } // 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值 const user = { ...results[0], password: '', user_pic: '' } // 对用户的信息进行加密,生成 Token 字符串 const tokenStr = jwt.sign(user, config.jwtSecretKey, { expiresIn: config.expiresIn, // token 有效期为 72 个小时 }) res.send({ status: 0, message: '登录成功!', // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀 token: 'Bearer ' + tokenStr, }) })}// 显示图片exports.image = (req, res) => { // console.log(__dirname) // res.sendFile(path.join(__dirname, 'public/image')); res.sendFile(path.join(process.cwd(), '/public/image/' + req.query.img)); // res.send('image ok') // console.log(process.cwd(),__dirname)}
加密:
const db = require('../db/index')// 获取所有用户exports.getUserall = (req, res) => { const sql = `select * from users where user_id!=?` // console.log(req.user.user_id) db.query(sql, req.user.user_id,function (err, results) { // console.log(err, results) if(err) return res.cc(err) res.send({ status: 0, message: '获取所有用户信息成功', list: results, }) }) // res.send('ok')}// 获取指定用户exports.getUserid = (req, res) => { const userinfo = req.url.split('=') const user_id = userinfo[userinfo.length - 1] const sql = `select * from users where user_id=?`; db.query(sql, user_id, (err, results) => { // 1. 执行 SQL 语句失败 if (err) return res.cc(err) // 2. 执行 SQL 语句成功,但是查询到的数据条数不等于 1 if (results.length !== 1) return res.cc('获取用户信息失败!') // 3. 将用户信息响应给客户端 res.send({ status: 0, message: '获取用户基本信息成功!', list: results[0], }) })}// 获取当前用户信息exports.getMyuser = (req, res) => { const sql = `select * from users where user_id=?`; db.query(sql, req.user.user_id, function (err, results) { if (err) return res.cc(err) if (results.length !== 1) return res.cc('获取用户信息失败!') // 将用户信息响应给客户端 res.send({ status: 0, message: '获取当前登录用户信息成功!', list: results[0], }) })}// 发布消息exports.setpublish = (req, res) => { // console.log(req.body.receive_id) // 接收表单数据 const articleInfo = { // 发布内容 ...req.body, // 信息发布时间 time: new Date(), // 发布者 id user_id: req.user.user_id, display_position: req.user.user_id + '' + req.body.receive_id } // console.log(articleInfo) const sql = `insert into chat_table set ?` db.query(sql, articleInfo,function (err, results) { // 执行 SQL 语句失败 if (err) return res.send({ status: 1, message: err.message }) // SQL 语句执行成功,但影响行数不为 1 if (results.affectedRows !== 1) { return res.send({ status: 1, message: '发布消息失败,请稍后再试!' }) } // 注册成功 // res.send({ status: 0, message: '发布成功!', list: req.body.content }) // console.log(req.body.receive_id,req.user.user_id) const sql = `select * from chat_table where state=0 and display_position=${req.user.user_id + '' + req.body.receive_id} or display_position=${req.body.receive_id + '' + req.user.user_id}`; db.query(sql, 0,function (err, results) { // 1. 执行 SQL 语句失败 if (err) return res.cc(err) // 3. 将用户信息响应给客户端 res.send({ status: 0, message: '发布成功!', list: results, }) }) })}// 获取指定信息exports.getMessage = (req, res) => { const userinfo = req.url.split('=') const user_id = userinfo[userinfo.length - 1] const sql = `select * from chat_table where state=0 and display_position=${req.user.user_id + '' + user_id} or display_position=${user_id + '' + req.user.user_id}`; db.query(sql, 0,function (err, results) { // 1. 执行 SQL 语句失败 if (err) return res.cc(err) // 3. 将用户信息响应给客户端 res.send({ status: 0, message: '获取信息成功!', list: results, }) })}// 更改用户信息exports.setMessage = (req, res) => { console.log(req.body,req.user.user_id) const sql = `update users set ? where user_id=?` db.query(sql, [req.body,req.user.user_id], (err, results) => { // 执行 SQL 语句失败 console.log(err) if (err) return res.cc(err) // 执行 SQL 语句成功,但影响行数不为 1 // if (results.affectedRows !== 1) return res.cc('修改用户基本信息失败!') // 修改用户信息成功 return res.cc('修改用户基本信息成功!', 0) })}
- 验证规则页面
const joi = require('joi')// 用户名的验证规则const username = joi.string().min(1).max(10).required()// 密码的验证规则// const password = joi.string().min(1).max(50).required()// 头像const image = joi.string()// 用户 id 的验证规则const user_id = joi.number().integer().min(1)// 状态const state = joi.string().valid('0', '1')// 注册和登录表单的验证规则对象exports.reg_login_schema = { // 表示需要对 req.body 中的数据进行验证 body: { username, // password, image, user_id, state },}
- 链接数据库页面
// 导入 mysql 模块const mysql = require('mysql')// 创建数据库连接对象const db = mysql.createPool({ host: '127.0.0.1', user: 'root', password: 'wang20030830', database: 'chat',})// 向外共享 db 数据库连接对象module.exports = db
- 加密页面
// 这是一个全局的配置文件module.exports = { // 加密和解密 Token 秘钥 jwtSecretKey: 'wangshihao No1. ^_^', // Token 的有效期 expiresIn: '72h'}
- package.json 页面
{ "name": "chat_node", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@escook/express-joi": "^1.1.1", "@hapi/joi": "^17.1.0", "bcryptjs": "^2.4.3", "cors": "^2.8.5", "express": "^4.17.1", "express-jwt": "^5.3.3", "fs": "^0.0.1-security", "joi": "^17.7.0", "jsonwebtoken": "^8.5.1", "multer": "^1.4.5-lts.1", "multiparty": "^4.2.3", "mysql": "^2.18.1", "path": "^0.12.7" }}
八、总结
以上就是 聊天框项目的所有功能简介和代码,不懂得可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog
来源地址:https://blog.csdn.net/weixin_62897746/article/details/128150447