美文网首页
Express+MySQL+Vue+Socket.io搭建一个聊

Express+MySQL+Vue+Socket.io搭建一个聊

作者: HolidayPeng | 来源:发表于2019-01-24 16:31 被阅读121次

    写这个系列的文章的初衷是想利用socket.io自己开发一个聊天室。聊天室要取到用户的头像和昵称,以及拉取历史聊天记录,就需要开发注册、登录、保存、获取聊天记录的功能。于是需要搭建一个后台服务,提供接口供前端调用,技术栈要用到Mysql和Express。

    本系列文章非手把手类型,而是从设计者的角度,阐述项目中遇到的问题和选择,以及如何解决这些问题,为什么这么选:

    一、后台接口项目是不是可以和Vue-Cli生成的前端项目合并成一个项目?如果可以,是把后端代码放到前端项目里,还是把前端代码放在后端项目里?

    我们先来看第一种:

    当我们用指令npm run dev把项目跑起来的时候,webpack会启动一个服务,并在本地的8080端口(默认)进行监听,这个时候,本地的静态资源(html、js、css、img等)会被打到这个地址,以便我们访问。

    这个功能是在Vue-Cli项目的build/webpack.dev.conf.js文件中进行配置的。具体是在devWebpackConfig对象里的devServer选项:

    devServer: {
        clientLogLevel: 'warning',
        historyApiFallback: {
          rewrites: [
            { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }
          ]
        },
        hot: true,
        contentBase: false, // since we use CopyWebpackPlugin.
        compress: true,
        host: HOST || config.dev.host,
        port: PORT || config.dev.port,
        open: config.dev.autoOpenBrowser,
        overlay: config.dev.errorOverlay
          ? { warnings: false, errors: true }
          : false,
        publicPath: config.dev.assetsPublicPath,
        proxy: config.dev.proxyTable,
        quiet: true, // necessary for FriendlyErrorsPlugin
        watchOptions: {
          poll: config.dev.poll
        }
      }
    

    既然webpack已经帮我们搭建了一个服务,我们也可以在这个服务里加上一个中间件,来给前端页面提供数据接口:


    来自webpack官方文档

    在devServer的before对象里,我们可以像上图webpack官方文档所描述的那样去moke数据,也可以用下面的方法连接数据库,从数据库中获取真实数据:

    // webpack.dev.config.js
    const express = require('express')
    const mysql = require('mysql')
    const app = express()
    const bodyParser = require('body-parser')
    const conn = mysql.createConnection({
      host: '127.0.0.1',
      user: 'root',
      password: 'password',
      database: 'test',
      multipleStatements: true
    })
    app.use(bodyParser.json())
    app.use(bodyParser.urlencoded({ extended: false }))
    ……
    const devWebpackConfig = merge(baseWebpackConfig, {
      ……
      devServer: {
        before (app) {
          app.all('*', (req, res, next) => {
            res.header('X-Powered-By', '3.2.1')
            res.header('Cache-Contrl', 'no-store')
            next()
          })
          app.disable('etag')
          app.get(`/api/getUser`, (req, res) => {
            const sqlStr = 'select * from user'
            conn.query(sqlStr, (err, results) => {
              if (err) {
                return res.json({
                  err_code: 1,
                  message: '资料不存在',
                  affextedRows: 0
                })
              }
              res.json({
                err_code: 200,
                message: results,
                affextedRows: results.affextedRows
              })
            })
          })
        },
      ……
      }
    ……
    })
    ……
    

    这样写的好处是解决了跨域的问题,但是后端的逻辑和webpack的配置混在一起,耦合紧密,不利于后期管理维护。

    那么把前端代码放在后端的项目里又会是什么情况呢?

    随便在网上搜了一下,确实有这样的项目模板,比如https://github.com/southerncross/vue-express-dev-boilerplate,他的目录结构如下:

    .
    ├── LICENSE
    ├── README.md
    ├── index.js
    ├── nodemon.json
    ├── package.json
    ├── src
    │   ├── client
    │   │   ├── App.vue
    │   │   ├── components
    │   │   │   └── Hello.vue
    │   │   └── index.js
    │   └── server
    │       ├── index.js
    │       ├── public
    │       │   └── favicon.ico
    │       ├── router.js
    │       └── views
    │           ├── error.jade
    │           └── index.jade
    └── webpack.config.js
    

    在webpack.config.js中,他将vue项目中的入口文件index.js打包生成的build.js放在了服务模块public静态文件夹的javascripts中:

    module.exports = {
      entry: path.join(__dirname, 'src/client/index.js'),
      output: {
        path: path.join(__dirname, 'src/server/public/javascripts/'),
        publicPath: '/javascripts/',
        filename: 'build.js'
      }
    ……
     }
    

    再在src/server/views/index.jade中,引入build.js文件:

    doctype html
    html
      head
        title= title
      body
        #app
        script(src='/javascripts/build.js')
    

    这样做的好处是,前后端代码在同一个服务上,但逻辑分开写在两个文件夹里,不仅解决了请求接口的跨域问题,也便于后台的中间件对页面请求做一些统一的处理。

    接下来我们再躯体考虑后台项目部分:

    二、Express项目的结构怎么设计?

    如下图所示,当前项目主要分为四层:db层存放数据库层面的逻辑,包括连接和mysql语句;model层存放操作数据库的方法;controller层处理接口的业务逻辑;routes层封装接口。


    项目结构图

    项目结构搭好了,我们来看具体的业务逻辑:

    三、注册流程是怎样的?需要几个接口?

    见下图:


    注册流程
    接口逻辑

    接口层面的问题解决了,我们再来看数据库层面:

    四、注册需要几张表?要保存哪些字段?

    最开始设计的是两张表,user表和email表。email表用来保存用户注册时的昵称、密码、邮件地址、验证码、过期时间等,当他完成注册以后成为正式用户,再把这其中的昵称、密码和邮箱地址保存在user表里。也就是说,user表里保存的是正式用户,email表里保存发送过邮件的用户:


    user表
    email表

    但是这样的设计并不是最合理的,首先两张表有重合的字段,会造成数据冗余;其次当这些重合的字段有变化的时候,两张表都需要更新。于是调整表结构为一张表,即用户表,注册成功与否用一个字段status来表示:


    合并后的user表

    然鹅,当数据库小白的我满怀信心带着表结构跑去请教大牛时,被告知这样的结构还是不合理,因为verification_code、verification_code_expired_time这两个字段保存在用户表里,对用户来说没有意义,应该分离开来。

    根据大牛的建议,最后的表结构如下:


    新user表
    新email表

    以上从项目设计、项目结构、业务逻辑、接口和数据库的设计,由整体到细节作了阐释,下一篇将从继续细节入手,对项目的登录部分进行分析,尽请期待……

    相关文章

      网友评论

          本文标题:Express+MySQL+Vue+Socket.io搭建一个聊

          本文链接:https://www.haomeiwen.com/subject/avcrjqtx.html