这里写目录标题

  • express-generator作用
  • 安装(全局安装)
  • 局部安装 nodemon 热更新
  • 使用步骤
  • 二级路由
  • 练习:用post请求获取到用户输入的账户,密码
  • 路由模块封装
  • 数据库连接池
  • 实例:服务端(后端)实现分页请求步骤
  • 实例登录注册的存数据库逻辑


项目开发:(这是一种规范)
1. 开发环境 dev(development) : npm run dev
2. 生产环境 build(production): npm run build
3. 测试环境 test(test): npm run test (了解, 后期专门的测试工具, 测试岗位)

Express 和 Express-generator的区别

Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。

Express-generator是Express的应用生成器,通过使用生成器工具,可以快速创建一个Express的应用骨架。

“express-generator是app engerator,即骨架生成器。以前的版本中,express-generator和express是在一块的,最近版本已经独立开来了。”

express-generator作用

通过应用生成器工具 express-generator 可以快速创建一个应用的骨架

安装(全局安装)

npm i express-generator -g

(全局安装后,在这台电脑就不用重复输入这个命令) 安装完成后,可以使用 express 命令 搭建项目; 会自动生成一个项目结构

//  语法规则
express 模板引擎 项目名称
//  案例
express -e myapp

这里的-e指的是ejs模板引擎的简写

接着按照它的指示操作

express生成验证码图片_sql

cd myapp

安装依赖

npm install 
npm i (简写)

运行项目是如下

npm run start

会生成如下一个文件夹

express生成验证码图片_node.js_02


如果还需要什么插件可以后续在下载 npm i 包名 --save

局部安装 nodemon 热更新

  1. 安装
npm i nodemon --save
  1. 安装完成,需要配置 启动命令, 在package.json文件中的“scripts”字段中配置启动命令
"scripts":{
   "dev":"nodemon ./bin/www"
}
  1. 配置完成后可以使用 npm run dev 启动服务

功能介绍

express生成验证码图片_express生成验证码图片_03

使用步骤

更改服务器默认的端口号在bin>www (文件里面)

首先引入路由配置文件,进行路由匹配

app.js文件是一个总页面是顶级路由,可以在里面引入你需要的页面

express生成验证码图片_big data_04


req是客户端向服务器(黑窗口)请求

res是服务器(黑窗口)像客户端进行响应

next是放行

var router = express.Router();创建一个路由容器

express生成验证码图片_express生成验证码图片_05


res.render(' ejs模板引擎名')会进入这个模板名的ejs文件

(这里res.send()方法是服务器像客户端响应的数据)

express生成验证码图片_node.js_06

这样就完成了一个基础的运行机制(这是一个对一个模块的导出.app.use中,routes文件夹有几个js文件就引入了几次)
可以在ejs模板引擎中书写主体,这是前后端不分离的做法

二级路由

下一篇文章有动态路由介绍

:如果我们在list.js文件下在建立一个admin路由,就要这样访问,相当于二级路由`
http://localhost:3000/list/admin

express生成验证码图片_big data_07

express生成验证码图片_测试工具_08

express生成验证码图片_node.js_09


只有index.js文件夹中的路由是可以直接匹配使用,除了index.js以外的路由模块中的路由都需要和app.js中的路由进行拼接使用

练习:用post请求获取到用户输入的账户,密码

app.js部分 引入路由配置文件

var listRouter = require('./routes/login');
app.use('/login', loginRouter);

ejs部分
小知识:当你直接就在自己本项目请求的,就不用写http://localhost:3000,可以直接写你的路由地址/login/dologin 当然你如果写完整,也不会出错

url: 'http://localhost:3000/login/dologin',
<body>
    <p class="err"></p>
    <p>
        <input type="text" name="user" class="user">
    </p>
    <p>
        <input type="password" name="pwd" class="pwd">
    </p>
    <p>
        <button>登录</button>
    </p>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        $('button').click(function() {
            $.ajax({
                url: 'login/dologin',
                type: 'post',
                data: {
                    user: $('.user').val(),
                    pwd: $('.pwd').val(),
                },
                success: function(data) {
                    console.log(data);
                    if (data.code == 400) {
                        $('.err').text(data.message)
                    } else if (data.code == 200) {
                        console.log(data);
                        //  存储用户信息
                        localStorage.setItem('user', data.data.name)
                            //  页面重定向                        
                        location.href = '/'
                    }
                }
            })
        })
    </script>

二级路由部分

因为从连接池传过来的query(数据库)是一个promise对象,所以它有then方法

var express = require('express');
 const query = require('../utils/query')
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('login');
});


//  next 放行
router.post('/dologin', (req, res, next) => {
    console.log(req.body);
    let {user, pwd} = req.body;
    query('select * from admin where name = ? and pwd = ?', [user, pwd]).then(data => {
        if(data.length){
            delete data[0].pwd
            res.send({
                code:200,
                message:'登录成功',
                data:data[0]
            })
        }else{
            res.send({
                code:400,
                message:'用户名或密码错误',
                data:[]
            })
        }
    })
    
})

module.exports = router;

express生成验证码图片_big data_10

使用 console.log(req.body); //将用户信息输出到控制台

express生成验证码图片_big data_11


对后端如何使用数据库连接池的解释

express生成验证码图片_sql_12

路由模块封装

解决二级路由的嵌套

这样就不用在app.js里面多次引入路由配置文件

express生成验证码图片_sql_13

打开服务器后

可以通过api来测试接口是否畅通

express生成验证码图片_node.js_14


express生成验证码图片_node.js_15

数据库连接池

对数据库的封装
通常会在app.js同级文件夹下建一个utils文件夹里面放query.js文件,这是一种规范,不是必须的

本来可以连接10个 connectionLimit: 10,下面释放资源的目的connection.release()是让别人还可以继续使用连接

const mysql = require('mysql');
//  创建连接池
const pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'yunmeng',
    connectionLimit: 10
})

module.exports = (sql, value = []) => {
    return new Promise((resolve, reject) => {
        //  从连接池中获取连接
        pool.getConnection((err, connection) => {
            if (err) {
                reject(err);
                throw err;
            }
            //  连接成功 执行查询
            connection.query(sql, value, (err, result) => {
                //  立刻释放资源(连接)
                connection.release()
                if (err) {
                    reject(err);
                    throw err;
                }
                //  sql执行成功
                resolve(result)
            })
        })
    })
}

这是没学连接池前的写法
数据库模块讲过query方法可以执行数据库的增删改查

module.exports = (sql, value = []) => {
   return new Promise((resolve, reject) => {
        pool.query(sql, value, (err, result) => {
         if (err) {
             reject(err);
              throw err;
       }
          resolve(result)
       })
    })
}

不论哪种写法;在用到数据库的地方都要引入模块
(自定义的·模块引用时需要加点斜杠,内置模块和第三方模块引入时,直接引入名字

const query = require('../utils/query')

实例:服务端(后端)实现分页请求步骤

首先是服务端把页分好,然后把数据传到客户端,下面是初步的想法

express生成验证码图片_big data_16


currentPage可以返回当前页码

currentPage: page

后端

var express = require('express');
const query = require('../utils/query');
var router = express.Router();
/* GET home page. */
router.get('/', async function(req, res, next) {
    //请求第一页的1页的数据
    let { page = 1 } = req.query;
    let length = 10;
    //总数据条数
    let total_sql = 'select * from t_order'
    let pageNum = await query(total_sql);
    // console.log(pageNum);输出所有的数据完整的
    //换算一共显示多少页
    let num = Math.ceil(pageNum.length / length)
    console.log(num);
    let sql = `select * from t_order limit ${(page-1)*length},${length}`
    let datalist = await query(sql);
    // console.log(datalist);
    res.render('index', { data: datalist, pageNum: num, currentPage: page });
});
module.exports = router;

数据库

const mysql = require('mysql');
//创建连接池
const pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'yunmeng',
    connectionLimit: 10
})

module.exports = (sql, value = []) => {
    //执行成功调用resolve.执行失败调用reject
    return new Promise((resolve, reject) => {
        //  从连接池中获取连接
        pool.getConnection((err, connection) => {
            if (err) {
                reject(err);
                throw err;
            }
            //  连接成功 执行查询
            connection.query(sql, value, (err, result) => {
                //  立刻释放资源(连接)
                connection.release()
                if (err) {
                    reject(err);
                    throw err;
                }
                //  sql执行成功
                resolve(result)
            })
        })
    })
}

//旧写法
// const mysql = require('mysql');

// const conn = mysql.createConnection({
//     host: 'localhost',
//     user: 'root',
//     password: 'root',
//     database: 'yunmeng'
// })

// module.exports = (sql, value = []) => {
//     return new Promise((resolve, reject) => {
//         conn.query(sql, value, (err, result) => {
//             if (err) {
//                 reject(err);
//                 throw err;
//             }
//             resolve(result)
//         })
//     })
// }

ejs模板

<style>
    .pagebean a {
        font-size: 20px;
        color: #333;
        float: left;
        padding: 10px;
        border: 1px solid #333;
        margin: 5px;
        text-decoration: none;
    }
    
    .pagebean .active {
        color: red;
        border-color: red;
    }
</style>

<body>
    <!-- 页面首次加载,渲染第一页数据 -->
    <div class="wrap">
        <ul>
            <% data.forEach((item,index)=>{%>
                <li>
                    <p>
                        作者:
                        <%= item.title%>
                    </p>
                    <p>
                        类型:
                        <%= item.classify%>
                    </p>
                </li>
                <%  })%>

        </ul>
    </div>
    <div class="pagebean">
        <!-- 页面数量 分页按钮的数量(根据数据库内容的条数来定) -->
        <% for(let i = 0;i<pageNum;i++) {%>
            <a href="/?page=<%= (i + 1)%>" class="<%= currentPage == (i+1)?'active':''%>">
                <%= (i+1)%>
            </a>
            <% }%>
    </div>

</body>

这样就从服务端完成了分页请求

补充:

如果ejs模板需要引入外部的样式css

就在public里面的stylesheets里面新建css样式文件

使用时不需要加…/public前缀,加了会链接不上

express生成验证码图片_express生成验证码图片_17

实例登录注册的存数据库逻辑

const query = require('../utils/query')
module.exports = (router) => {
    //登录部分
    router.post('/dologin', async(req, res, next) => {
            let { phone, pwd } = req.body;
            let sql_phone = 'select * from user where phone = ?'
            let result_name = await query(sql_phone, [phone])
            if (result_name.length) {
                let sql = 'select * from user where phone = ? and password = ?';
                let result = await query(sql, [phone, pwd]);
                if (result.length) {
                    delete result[0].password
                    res.send({
                        code: 200,
                        message: 'success',
                        data: result
                    })
                } else {
                    res.send({
                        code: 400,
                        message: '用户名或密码错误',
                        data: []
                    })
                }
            } else {
                res.send({
                    code: 400,
                    message: '用户名或密码错误',
                    data: []
                })
            }

        })
        //注册部分
        .post('/doregister', (req, res, next) => {
            let { user, pwd, phone } = req.body;
            console.log(req.body);
            let sql = 'insert into user set ?';
            query(sql, { nickname: user, password: pwd, phone }).then(result => {
                if (result.affectedRows) {
                    res.send({
                        code: 200,
                        message: '注册成功'
                    })
                } else {
                    res.send({
                        code: 400,
                        message: '注册失败'
                    })
                }
            })
        })
}

result.affectedRows 是改变的行,所以有affectedRows方法

let sql = 'insert into user set ?';
query(sql, { nickname: user, password: pwd, phone }).then(result=>{})

这里面可以传一个值,也可以传对象
send
前后端分离传递的参数在send里面
不分离的是render匹配页面和放传递的参数
你别搞混了