记录工作中的点点滴滴

手把手教你开发nodejs微博网站-用户注册篇

引子

  • 上一篇主要讲解了本项目开发使用的数据库MongoDb,MongoDB 的可视化管理工具Robomongo,MongoDB 的驱动库Mongolass,已经具备了功能开发的基本条件。
  • 本篇我主要讲解用户注册功能的开发。

目录结构

在正式开发之前,我们先来看一下项目的目录结构,如下:
directory

目录说明

对应的主要文件及文件夹用处如下说明:

  1. app.js: 程序主文件
  2. models: 存放操作数据库的文件
  3. package.json: 存储项目名称、描述信息、作者、依赖等等信息
  4. public: 存放静态文件,如样式、图片等
  5. routes: 存放路由文件
  6. views: 存放模板文件

Tip

我们遵循了MVC的开发模式:

  • 控制器(Controller),一组行为的集合
  • 模型(Model),数据相关的操作和封装
  • 视图(View),视图的渲染
    对MVC不太熟悉的童鞋可以自行查找一下资料,我这里不再赘述了。

    配置文件

  • 不管是大型项目,还是小型项目,将配置文件与代码分离开来都是一个比较好的做法。
  • 我们通常将配置写到一个配置文件里,如 config.js 或 config.json ,并放到项目的根目录下。
  • 但通常我们都会有许多环境,如本地开发环境、测试环境和线上环境等,不同的环境的配置不同,我们不可能每次部署时都要去修改引用 config.test.js 或者 config.production.js
config-lite

config-lite 模块正是你需要的。关于config-lite的介绍和使用可以点这里: config-lite
config-lite 会根据环境变量(NODE_ENV)的不同从当前执行进程目录下的 config 目录加载不同的配置文件。如果不设置 NODE_ENV,则读取默认的 default 配置文件,如果设置了 NODE_ENV,则会合并指定的配置文件和 default 配置文件作为配置,config-lite 支持 .js、.json、.node、.yml、.yaml 后缀的文件。

安装config-lite
1
npm i config-lite --save

即可。

建配置文件

在根目录下面,新建config/default.js文件,代码如下:

1
2
3
4
5
6
7
8
9
module.exports = {
port : 3000,
session : {
secret: 'myblog',
key: 'myblog',
maxAge: 2592000000
},
mongodb: 'mongodb://localhost:27017/myblog'
};

参数解释:

  • port: 程序启动时要监听的端口号
  • session:express-session 的配置信息,后面会介绍
  • mongodb:mongodb 的地址,myblog 为 db 名

    express-session

    由于 HTTP 协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是会话(Session)。关于会话(Session)的介绍在网上有比较多的资料,大家可以自行查找。

    我们通过引入express-session中间件来实现对会话的支持。

    安装 express-session
    1
    npm i express-session --save
    使用express-session
    1
    2
    var session = require('express-session')
    app.use(session(options))

    使用给出的配置项来创建一个会话中间件。

    更多关于options的详细参数可以看API

    解释

    session 中间件会在 req 上添加 session 对象,即 req.session 初始值为 {},当我们登录后设置 req.session.user = 用户信息,返回浏览器的头信息中会带上 set-cookie 将 session id 写到浏览器 cookie 中,那么该用户下次请求时,通过带上来的 cookie 中的 session id 我们就可以查找到该用户,并将用户信息保存到 req.session.user。

    express-formidable

    我们的注册功能里要求想要注册的用户必须上传头像,所以用到了上传功能。

  • Express是一个快速的,不收约束的,简约的nodejs的web框架;
  • Formidable是一个解析表单数据的nodejs模块,包括多部分/格式文件上传;
  • 所以,express-formidable是他们之前的一座桥梁,是一个强大的Express中间件

    使用express-formidable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const express = require('express');
    const formidable = require('express-formidable');
    var app = express();
    app.use(formidable());
    app.post('/upload', (req, res) => {
    req.fields; // contains non-file fields
    req.files; // contains files
    });
  • 不包含文件的字段值使用 req.fields来接收;

  • 文件字段的值使用req.files来接收;

    配置项
    1
    app.use(formidable(opts));

    例如:

    1
    2
    3
    4
    5
    app.use(formidable({
    encoding: 'utf-8',
    uploadDir: '/my/dir',
    multiples: true, // req.files to be arrays of files
    });

    注:想了解更多,可以点击这里

    用户模型设计

    用户注册时,需要的字段有:

  1. 用户名
  2. 用户密码
  3. 用户确认密码
  4. 用户性别
  5. 用户微博头像
  6. 用户简介

    在了解了基本字段后,我们在lib/mongo.js里添加如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 用户模型设计
    exports.User = mongolass.model('User',{
    name : {type : 'string'},
    password : {type : 'string'},
    gender : {type : 'string',enum : ['m','f','x']},
    avatar : {type : 'string'},
    intro : {type : 'string'}
    });
    exports.User.index({ name : 1},{unique : true}).exec(); // 根据用户名找到用户,用户名全局唯一

    说明

  • 我们创建了用户的schema
  • 生成并导出了User这个model
  • 设置name为唯一索引,防止用户名重复

    摞代码

    好了,到这一步,差不多该准备的工作都准备完了,那么就开始到编码阶段。

    用户注册页

    在views/reg.js里添加如下代码:

    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
    <%- include('header') %>
    <form class="well form-horizontal" method="post" enctype="multipart/form-data">
    <fieldset>
    <legend>用户注册</legend>
    <div class="form-group" style="padding-left:15px">
    <div style="float:left">
    <label class="control-label" for="name">用户名</label>
    </div>
    <p class="text-danger" style="color:red">*</p>
    <div class="controls">
    <input type="form-control" class="form-control" id="name" name="name"
    style="width:20%;" placeholder="用户名">
    <p class="help-block">你的帐号的名称,用于登录和显示</p>
    </div>
    </div>
    <div class="form-group" style="padding-left:15px">
    <div style="float:left">
    <label class="control-label" for="password">密码</label>
    </div>
    <p class="text-danger" style="color:red">*</p>
    <div class="controls">
    <input type="password" class="form-control" id="password" name="password"
    style="width:20%;" placeholder="密码">
    </div>
    </div>
    <div class="form-group" style="padding-left:15px">
    <div style="float:left">
    <label class="control-label" for="repassword">重复密码</label>
    </div>
    <p class="text-danger" style="color:red">*</p>
    <div class="controls">
    <input type="password" class="form-control" id="repassword" name="repassword"
    style="width:20%;" placeholder="再次输入密码">
    </div>
    </div>
    <div class="form-group" style="padding-left:15px">
    <div style="float:left">
    <label class="control-label" for="gender">性别</label>
    </div>
    <p class="text-danger" style="color:red">*</p>
    <div class="controls">
    <select class="form-control" name="gender" style="width:20%">
    <option value="m"></option>
    <option value="f"></option>
    <option value="x">保密</option>
    </select>
    </div>
    </div>
    <div class="form-group" style="padding-left:15px">
    <div style="float:left">
    <label class="control-label" for="exampleInputFile">头像</label>
    </div>
    <p class="text-danger" style="color:red">*</p>
    <div class="controls">
    <input type="file" id="exampleInputFile" name= "avatar">
    </div>
    </div>
    <div class="form-group" style="padding-left:15px">
    <div style="float:left">
    <label class="control-label" for="introduction">简介</label>
    </div>
    <p class="text-danger" style="color:red">*</p>
    <div class="controls">
    <textarea class="form-control" rows="5" id="introduction" name="intro"
    style="width:60%"></textarea>
    </div>
    </div>
    <button type="submit" class="btn btn-primary">注册</button>
    </fieldset>
    </form>
    <% include footer.ejs %>
    路由文件

    在routes目录下新建reg.js文件,代码如下:

    1
    2
    3
    4
    5
    6
    // 用户注册
    router.get('/',function (req, res, next) {
    res.render('reg', {
    title: '用户注册'
    });
    });

    现在访问:localhost:3000/reg 可以看到用户注册页的效果了,如下图:
    用户注册
    未完待续,敬请关注