• 基于Vue+nodejs+Element-ui的聊天框项目


    一、项目简介

    本项目基于纯前端(移动端)技术开发一个聊天系统,界面美观大方,采用Nodejs+Vue+ElemenetUI开发实现,主要包含:登录注册,修改个人资料,更改头像,发送消息,单对单聊天等。

    二、环境介绍

    语言环境:nodejs

    数据库:MySQL

    应用服务器:nodejs

    开发工具:vscode

    开发技术:nodejs+vue+elementUI

    三、系统展示

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    四、视频功能展示

    基于Vue+nodejs+Element-ui的聊天系统项目

    五、前端核心代码展示

    • 头部导航功能代码
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 登录注册页居中旋转功能代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 登录页代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 注册页代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 我的主页代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 修改个人信息代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 聊天框内容代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 好友页代码
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 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: {
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 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"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 移动端代码
    const WIDTH = 375//如果是尺寸的设计稿在这里修改
    const setView = () => {
        //设置html标签的fontSize
        document.documentElement.style.fontSize = (100 * document.documentElement.clientWidth / WIDTH) + 'px'
    }
    window.onresize = setView
    setView()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 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 = axios
    Vue.use(ElementUI);
    Vue.config.productionTip = false
    
    new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    六、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')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 接口页面

    不加密

    // 导入 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    加密:

    // 导入 express
    const 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 接口内容页面

    不加密:

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    加密:

    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)
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 验证规则页面
    const joi = require('joi')
    
    /**
     * string() 值必须是字符串
     * alphanum() 值只能是包含 a-zA-Z0-9 的字符串
     * min(length) 最小长度
     * max(length) 最大长度
     * required() 值是必填项,不能为 undefined
     * pattern(正则表达式) 值必须符合正则表达式的规则
     */
    
    // 用户名的验证规则
    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
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 链接数据库页面
    // 导入 mysql 模块
    const mysql = require('mysql')
    
    // 创建数据库连接对象
    const db = mysql.createPool({
      host: '127.0.0.1',
      user: 'root',
      password: 'wang20030830',
      database: 'chat',
    })
    
    // 向外共享 db 数据库连接对象
    module.exports = db
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 加密页面
    // 这是一个全局的配置文件
    module.exports = {
        // 加密和解密 Token 秘钥
        jwtSecretKey: 'wangshihao No1. ^_^',
        // Token 的有效期
        expiresIn: '72h'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 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"
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    八、总结

    以上就是 聊天框项目的所有功能简介和代码,不懂得可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
    我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog

  • 相关阅读:
    手机域名是什么?
    【LeetCode】Day183-数组的均值分割
    【Swift 60秒】12 - Arrays vs Sets vs Tuples
    黑客(网络安全)技术自学30天
    RxJS 实做: 自定义 operator - switchMapBy
    lv4 嵌入式开发-4 标准IO的读写(二进制方式)
    HelloSpring
    Java项目:SSM的网上购物商城系统
    M-LVDS收发器MS2111可pin对pin兼容SN65MLVD206
    游戏心理学Day15
  • 原文地址:https://blog.csdn.net/weixin_62897746/article/details/128150447