首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Node.js 配合 express 框架、mongodb 实践 && [使用 TypeScript 重构]

Node.js 配合 express 框架、mongodb 实践 && [使用 TypeScript 重构]

作者头像
Peter谭金杰
发布2019-08-02 16:27:13
4.9K0
发布2019-08-02 16:27:13
举报

一、Node.js默认使用commonJs的模块化方案,TypeScript默认是ES6的模块化方案,两者有本质区别。

  • 1.Node.js的去寻找引入的依赖时,如果是Node自带的模块,比如fs文件模块,只需要填写fs即可。如果是自己定义的模块,那么需要加入./(使用相对路径),暴露接口使用exports或者module.exports
  • 2.TypeScript的 import * from url 的引入依赖,需要填写完整的相对路径,否则是找不到模块的,暴露接口使用export .
  • 3.Node中使用TypeScript需要下一些包去支持,比如express框架这些,还有一些支持内置对象的包:
  • 4.github源码下载地址
 "dependencies": {
    "@babel/core": "^7.4.0",
    "@types/core-js": "^2.5.0",
    "browserify": "^16.2.3",
    "connect-mongo": "^2.0.3",
    "cookie-parser": "^1.4.4",  
    "ejs": "^2.6.1",
    "express": "^4.16.4",
    "express-session": "^1.15.6",
    "mongoose": "^5.4.19",
    "nodemon": "^1.18.10",
    "sha1": "^1.1.1"
  },
  "devDependencies": {
    "@types/express": "^4.16.1",
    "@types/node": "^11.11.4",
    "ts-loader": "^5.3.3",
    "ts-node-dev": "^1.0.0-pre.32",
    "typescript": "^3.3.4000",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0"
  }

 '具体还需要什么,可以上网去搜索下'

二、入口文件,我们使用 ejs 引擎渲染( res.render() )

  • 1.Node.js使用ejs渲染的核心技巧是渲染数据的指定
  • 2.尽量一个渲染数据对象包括所有的渲染内容
  • 3.一个渲染对象可以有很多个属性,每次get请求时先发送一个空的对象到后端,再根据需求逻辑指定 对象属性和内容,最后还是传输那个对象回来。避免了 传送过多的对象,代码看起来很复杂
  • 4.渲染数据的位置在渲染的ejs文件中的放置, 如果需要样式,可以事先在HTML结构中包一层HTML结构, 然后用CSS定义好。
 '这是Node.js版本'
 
 '//入口文件使用了两个路由器路由,分别处理get和post请求逻辑。
 即使是同一个路由,但是请求方式不一样,他们的处理逻辑不会冲突'
const express = require('express');
const db = require('./common/db');
const app = express();
const uirouter = require('./router/uirouter');
const postrouter = require('./router/postrouter');
app.set('views', 'views');
app.set('view engine', 'ejs');

db.then(() => {
    app.use(uirouter);
    app.use(postrouter);
})

app.listen(8080, err => {
    if (!err) {
        console.log('端口号监听成功')
    } else {
        console.log('端口监听失败', err)
    }
})


-----------------

'这是TypeScript版本'

import express from './node_modules/@types/express/index';
import db from './common/db1';
import uirouter from './router/uirouter1';
import postrouter from './router/postrouter1';
const app: any = express();
app.set('views', 'views');
app.set('view engine', 'ejs');
db.then((): void => {
    app.use(uirouter);
    app.use(postrouter);
});
app.listen(8080, (err): void => {
    if (!err) {
        console.log('服务器连接成功');
    } else {
        console.log('服务器连接成功');
    };
});

三、get请求的路由处理模块

  • 1.路由模块的核心,一个路由处理一个逻辑
  • 2.res.end / send / render 后面再写逻辑也不会执行了,因为已经返回响应。
  • 3.对于cookie的使用我们需要依赖第三方中间件
  • 4.res.render()里面是写ejs渲染的文件,所以可以不用写ejs的后缀
  • 5.res.redirect()里面写的是定向的那个路由,指定前往那个路由,

然后根据那个路由的逻辑处理,此时浏览器中的url会改变。这就叫重定向

'//这里我们使用了第三方中间件处理cookie并且
携带数据,大概设计思路:
1.没有登录过不能进入个人中心,会跳转到登录界面
2.登录过后会有一个免登录期限进入个人中心
3.在登录界面可以通过用户名和邮箱找回密码
4.在 Node 端处理逻辑,只有res.redirect()可以
改变浏览器的网址,切记。
5.每个路由器路由代表每个不同的逻辑
6.get模块只处理渲染哪个页面的逻辑'
const { Router } = require('express');
const model = require('../common/model');
const cookieParse = require('cookie-parser');
const router = new Router();
router.use(cookieParse())
router.get('/index', (req, res) => {
    res.render('index.ejs', { err: "" })
})
router.get('/', (req, res) => {
    res.redirect('/index');
});
router.get('/login', (req, res) => {
    res.render('login.ejs', { err: "" });
});
router.get('/register', (req, res) => {
    res.render('register.ejs', { err: "" });
});
router.get('/reset', (req, res) => {
    res.render('reset.ejs', { err: '' });
});
router.get('/usercenter', async (req, res) => {
    const result = await model.findOne({ _id: req.cookies.userid });
    if (!result) {
        res.redirect('/login')
        return
    }
    res.render('usercenter.ejs', { err: "" });
});
module.exports = router;

四、post模块,处理各种数据库的CRUD操作,后台逻辑。(核心)

  • 1.CRUD操作全部依赖模型对象来执行。
  • 2.限制对象一旦生成那么无法改变,除非删除数据库
  • 3.限制对象的增删改查都返回的是一个promise对象,

如果这时候去 if() 里判断,无论有什么样的结果,都是true,

而且这个 CRUD 操作都是异步,所以我们把外部函数变成 async 函数,

这样可以配合 await 实现最佳异步,还可以获取他们的返回值进行

if 判断。(Node.js的后端核心)

const { Router } = require('express');
const express = require('express');
const model = require('../common/model');
const cookieParse = require('cookie-parser');
const sha1 = require('sha1');
const router = new Router();
router.use(cookieParse())
router.use(express.urlencoded({ extended: true }))
router.post('/login', async (req, res) => {
    const { username, password } = req.body;
    const result = await model.findOne({ username, password: sha1(password) });
    if (!result) {
        res.render('login', { err: { usernameloginerr: '用户名或密码错', username: username } })
        return;
    }
    const userid = result.id;
    res.cookie('userid', userid, {maxAge:1000*60*10});
    res.redirect('/usercenter')
    return
});
router.post('/register', async (req, res) => {
    const { username, password, repassword, email } = req.body;
    const err = {};
    const usernameReg = /^[A-Za-z0-9_]{5,10}$/;
    const passwordReg = /^[A-Za-z0-9_]{5,12}$/;
    const emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
    if (!usernameReg.test(username)) {
        err.usernamereerr = '用户名格式错误';
    }
    if (!passwordReg.test(password)) {
        err.passworderr = '密码格式错误';
    }
    if (repassword !== password) {
        err.repassworderr = '两次密码输入不一致';
    }
    if (!emailReg.test(email)) {
        err.emailerr = '邮箱格式错误';
    }
    const usernameresult = await model.findOne({ username });
    if (usernameresult) {
        err.usernamereerr = '用户名已存在';
        res.render('register', { err })
        return
    };
    const emailresult = await model.findOne({ email });
    if (emailresult) {
        err.emailerr = '邮箱已被注册';
        res.render('register', { err })
        return
    }
    if (err.usernamereerr || err.passworderr || err.repassworderr || err.emailerr) {
        err.username = username;
        err.email = email;
        res.render('register', { err })
        return
    }
    model.create({
        username: username,
        password: sha1(password),
        email: email
    })
    res.redirect('/index')
});
router.post('/reset', async (req, res) => {
    const { username, password, repassword, email } = req.body;
    const err = {};
    const result = await model.findOne({ username, email });
    if (!result) {
        if (repassword !== password) {
            err.repassworderr = '两次密码输入不一致'
        }
        err.usernamereerr = '用户名或者邮箱输入有误';
        err.emailerr = '用户名或者邮箱输入有误';
        res.render('reset.ejs', { err }) 
        return
    } else {
        await model.updateOne({ username, email }, { password: sha1(password) });
        res.redirect('/usercenter');
        return
    }

})
module.exports = router;

五、工具类模块 model对象和database模块 有 天坑 需要注意

限制对象一旦生成那么无法改变,除非删除数据库

'database模块'

const mongoose = require('mongoose');
module.exports = new Promise((resolve, reject) => {
    mongoose.connect('mongodb://localhost:27017/userinfos', { useCreateIndex: true, useNewUrlParser: true });
    mongoose.connection.once('open', err => {
        if (!err) {
            console.log('数据库连接成功')
            resolve()
        } else {
            console.log('数据库连接失败', err)
            reject(err)
        }
    })
})

------

'model对象模块'
 '这里定义限制对象时,一定要考虑好,
 否则数据库连接启动后,除非删除数据库,
 不然无法修改限制对象的内容!!!!'
const { Schema, model } = require('mongoose');
const ajaxschema = new Schema({
    username: {
        type: String,
        unique: true,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    email: {
        type: String,
        unique: true,
        required: true
    },
})
const model1 = model('userinfo', ajaxschema);
module.exports = model1;

六、 ejs 的渲染目录

  • ejs 的渲染数据在ejs文件中的格式有三种
  • 1. <% data %> 里面可以写任意代码
  • 2. <%= data %> 里面写的代码最终会转义后再出现(推荐)
  • 3. <%- data %> 里面写的代码最终不会转义后就出现(不安全)
'index.ejs '


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>欢迎来到首页</h1>
    <a href="http://localhost:8080/login">登陆</a>
    <a href="http://localhost:8080/register">注册</a>
    <a href="http://localhost:8080/usercenter">个人中心</a>
</body>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script>

</script>

</html>

-------


'login.ejs'

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form method="post" action="/login">
        <label for="username">用户名</label>
        <input type="text" name="username" value=<%= err.username %>><%= err.usernameloginerr %> <br />
        <label for="password">密码</label>
        <input type="password" value="" name="password">
        <input type="submit" id="sub">
    </form>
    <a href='/reset'>找回密码</a> 
</body>
<script>
   
</script>

</html>

------------



'register.ejs'


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <form method="post" action="/register">
        <label for="usern ame">用户名</label>
        <input type="text"name="username"  value= <%=  err.username  %> > <%=  err.usernamereerr  %></br>
        <label for="password">密码</label>
        <input type="password" value="" name="password"> <%=  err.passworderr  %></br>
        <label for="repassword">再次确认密码</label>
        <input type="password" value="" name="repassword"> <%=  err.repassworderr  %></br>
        <label for="email">邮箱</label>
        <input type="text"  name="email" value= <%= err.email %> > <%=  err.emailerr  %></br>
        <input type="submit">
    </form>
</body>

</html>


-----------



'reset.ejs'

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form method="post" action="/reset">
        <label for="usern ame">您注册的用户名</label>
        <input type="text" name="username" value=<%=  err.username  %>> <%=  err.usernamereerr  %></br>
        <label for="password">重置后的密码</label>
        <input type="password" value="" name="password"> <%=  err.passworderr  %></br>
        <label for="repassword">请再次确认密码</label>
        <input type="password" value="" name="repassword"> <%=  err.repassworderr  %></br>
        <label for="email">您的注册邮箱</label>
        <input type="text" name="email" value=<%= err.email %>> <%=  err.emailerr  %></br>
        <input type="submit">
    </form>
</body>

</html>


------



'usercenter.ejs'


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>欢迎来到个人中心</h1>
    <a href="/index">返回主页</a>
</body>
</html>

------

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Node.js默认使用commonJs的模块化方案,TypeScript默认是ES6的模块化方案,两者有本质区别。
  • 二、入口文件,我们使用 ejs 引擎渲染( res.render() )
  • 三、get请求的路由处理模块
  • 四、post模块,处理各种数据库的CRUD操作,后台逻辑。(核心)
  • 五、工具类模块 model对象和database模块 有 天坑 需要注意
  • 六、 ejs 的渲染目录
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档