Node.js列表功能实现

983 阅读8分钟

这边文章是'小前端'学习完慕课网 Nodejs全栈入门 视频后总结的一篇使用nodejs写一个列表增删改查功能的小demo。主要介绍了nodejs和常用插件的api的使用。希望可以对初学node的小伙伴们有所帮助。

附上项目github地址:github.com/fangcheng14…

需求说明(api说明)

  1. 根据客户端传递过来的不同的参数(状态/页码)查询 任务的列表
  2. 实现 新增一个任务的功能(名称/截止日期/内容)
  3. 实现一个 编辑的功能:根据客户端传递的任务对象(已经存在的数据)进行编辑(名称/截止日期/内容)
  4. 删除一个任务(ID)
  5. 修改任务的状态(ID/状态--待办/完成)

一、项目搭建和相关api安装

1.创建项目和安装依赖

mkdir list_page_node // 创建一个名称为‘list_page_node’的文件夹
npm init -y // 项目初始化,生成一个默认的 package.json 文件
git init // 创建新的 Git 仓库
npm install express mysql2 sequelize sequelize-cli body-parser nodemon -S // 安装相关依赖

express:第一代最流行的web框架,它对Node.js的http进行了封装。
mysql2:node中使用的数据库。
sequelize:Sequelize 是一个基于 promise 的适用于 Node.js 和 io.js 的 ORM。
sequelize-cli:sequelize-cli工具
body-parser:中间件,用于接收post请求放在body中的参数。
nodemon:工具,可以自动检测到目录中的文件更改时通过重新启动应用程序来调试基于node.js的应用程序。


小问题为何使用mysql2而不是经典的mysql库?主要基于以下原因:

  • 更高的性能!
  • 支持PreparedStatement,多次查询性能更高,书写SQL更简单;
  • 自带Promise包装器,可以直接使用async/await语法;
  • 绝大部分api和mysql库兼容,意味着mysql的文档和线上资料亦可作为参考。

2.看下安装了哪些依赖

"dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "lodash": "^4.17.11", // 前后端都可以用到的工具库
    "moment": "^2.24.0", // 专门用来处理日期的
    "mysql2": "^2.2.5",
    "sequelize": "^6.6.2",
    "sequelize-cli": "^6.2.0"
 },

3.启动项配置

在根目录下新建src目录和及app.js入口文件

image.png

  "scripts": {
    "start": "nodemon src/app.js",
  },

二、框架代码编写

1.express框架应用编写

const express = require('express');
const app = express();

app.listen(3000, ()=>{
    console.log('server启动成功')
})

2.api框架编写

1.错误处理

// 1. 所有错误 http status == 500
app.use((err,req,res,next)=>{
    if(err) {
        res.status(500).json({
            "message": err.message
        })
    }
})

报错测试

app.get('/list',async (req,res,next)=>{
    next(new Error('自定义异常'))
})

2.查询任务列表

app.get('/list/:status/:page',async (req,res)=>{
    res.json({
        list:[]
    })
})

3.新增任务

// 引用body-parser中间件
const bodyParser = require('body-parser');

// 专门用来处理exoress json的
app.use(express.json());

// 用来对url参数做encoded处理
// for parsing application/xwww-form-urlencoded
app.use(express.urlencoded());

// 用来对body参数做encoded处理
// for parsing application/xwww-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));


app.post('/create',async (req,res)=>{
    let { name,deadline,content } = req.body;// 需要引用'body-parser'中间件处理
    res.json({
        todo:[],
        name,
        deadline,
        content
    })
})

4.修改任务

app.post('/update',async (req,res)=>{
    let { name,deadline,content,id } = req.body; // 需要引用'body-parser'中间件处理
    res.json({
        todo:[],
        name,
        deadline,
        content,
        id
    })
})

5.app.js代码总览

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

// 专门用来处理exoress json的
app.use(express.json());

// 用来对url参数做encoded处理
// for parsing application/xwww-form-urlencoded
app.use(express.urlencoded());

// 用来对body参数做encoded处理
// for parsing application/xwww-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

// 查询任务列表
app.get('/list/:status/:page',async (req,res)=>{
    res.json({
        list:[]
    })
})

// 创建任务
app.post('/create',async (req,res)=>{
    let { name,deadline,content } = req.body; // 需要引用'body-parser'中间件处理
    res.json({
        todo:[],
        name,
        deadline,
        content
    })
})

// 修改任务
app.post('/update',async (req,res)=>{
    let { name,deadline,content,id } = req.body; // 需要引用'body-parser'中间件处理
    res.json({
        todo:[],
        name,
        deadline,
        content,
        id
    })
})

// 修改任务、删除
app.post('/update_status',async (req,res)=>{
    let { id,status } = req.body; // 需要引用'body-parser'中间件处理
    res.json({
        todo:[],
        id,
        status
    })
})


// 1. 所有错误 http status == 500
app.use((err,req,res,next)=>{
    if(err) {
        res.status(500).json({
            "message": err.message
        })
    }
})

app.listen(3000, ()=>{
    console.log('server启动成功')
})

三、数据库的初始化

1.创建一个数据库

1.安装数据库

mac系统:mac系统可直接通过命令行brew包安装 (前提得给你的mac上安装brew,安装流程可见:macOS 安装Homebrew mac下镜像飞速安装Homebrew教程

// 安装
brew install mysql
// 查看电脑中有哪些服务
brew services list
// 启动mysql
brew services start mysql
// 关闭mysql
brew services stop mysql
// 登录连接mysql
mysql -u root -p

更多关于Mac系统安装MySQL的介绍可见:Mac 安装MySQL

Windows系统: Windows系统安装MySQL可见菜鸟教程介绍:MySQL 安装

2.新建一个数据库

打开Navicat,新建一个数据库

image.png

image.png

image.png

image.png

这样我们就建好一个数据库了。

2.初始化项目的数据库配置

我们可以在文件的根目录下新建一个文件夹用来存放数据库配置文件。

mkdir db // 新建文件夹 db
cd db
npx sequelize init

image.png

3.生成模型文件

npx sequelize model:generate --name List --attributes name:string,dedaline:date,content:string

image.png

4.持久化,模型对应的[数据库表]

npx sequelize db:migrate

即可在Navicat中看到我们新建的表和对应的字段了。 image.png

5.数据库表中添加新字段

第一步:db/models中找到对象表文件,在ListData.init下添加新字段。

image.png

第二步:db/migrations文件夹下找到对应的文件,在createTable下添加新字段。
其中,可以设置字段的默认值,defaultValue设置。

image.png

image.png 第三步:打开Navicat,删除在ListData表,清空SequelizeMeta表。

image.png

image.png

第四步:重新执行命令,在bg文件夹下:npx sequelize db:migrate

四、API具体实现(使用ORM模型)

1.导入模型

// 导入模型
const models = require('../db/models');
// models其实是一个对象 里面包含了: 
// {
//     [modal:listdate]
//     sequelize
//     Sequelize
// }

2.创建任务代码

create()方法

// 创建任务
app.post('/create',async (req,res,next)=>{
    try {
        let { name,deadline,content } = req.body; // 需要引用'body-parser'中间件处理
        // ListData 是你要操作的数据库中表的名称
        // create()API表示新增一条数据
        let data = await models.ListData.create({
            name,
            deadline,
            content
        })
        res.json({
            data,
            message: '创建成功'
        })
    } catch (error) {
        next(error);
    }
})

可以能会遇到一个报错

{
    "message": "Unknown column 'createdAt' in 'field list'"
}

原因:当初在创建数据库表的时候sequelize默认生成了createdAt和updateAt两个字段。
解决方案:在db/models文件夹下找到对应的表文件,加入’timestamps: false‘

image.png

3.修改任务代码

findOne()、update()方法

// 修改任务
app.post('/update',async (req,res,next)=>{
    try {
        let { name,deadline,content,id } = req.body;
        // findOne()API表示找到某一个
        let data = await models.ListData.findOne({
            where:{
                id
            }
        })
        // 判断是否找到该条数据 找到则执行更新功能
        if (data) {
            // 执行更新功能 update()API
            data = await data.update({
                name,
                deadline,
                content
            })
        }
        res.json({
            data
        })
    } catch (error) {
        next(error);
    }
})

4.修改任务状态、删除代码

findOne()、update()方法

// 修改任务状态、删除
app.post('/update_status',async (req,res,next)=>{
    try {
        let { id,status } = req.body;
        // findOne()API表示找到某一个
        let data = await models.ListData.findOne({
            where:{
                id
            }
        })
        // 判断找到该条数据 并且在status有修改时触发
        if (data && status != data.status) {
            // 执行更新功能 update()API
            data = await data.update({
                status
            })
        }
        res.json({
            data
        })
    } catch (error) {
        next(error);
    }
})

5.查询任务列表代码

findAndCountAll()方法

// 查询任务列表
app.get('/list/:status/:page',async (req,res,next)=>{
    // 1.状态: 1:代办 2:完成 3:删除 -1:全部
    // 2.分页
    try {
        // 获取url参数:req.params
        let { status,page } = req.params;
        let limit = 10; // 设置每页显示的数量
        let offset = (page - 1) * limit; // 每页开始的位置
        let where = {};
        if (status != -1) where.status = status; // 如果为-1则表示搜索全部

        // findAndCountAll() API表示查询并且汇集总数
        let list = await models.ListData.findAndCountAll({
            where,
            limit,
            offset
        })
        res.json({
            list,
            message: '列表查询成功'
        })
    } catch (error) {
        next(error);
    }
})

6.API总结

  • create(): 表示新增一条数据
  • findOne(): 表示找到某一个
  • update(): 更新功能
  • findAndCountAll(): 表示查询并且汇集总数

五、项目的发布和运维

1. pm2

pm2: nodejs 生产环境中的管理工具。

// 安装:
npm i pm2 -g
// 初始化项目启动、运维脚本:会生成一个配置文件(ecosystem.config.js)。
pm2 init

2. ecosystem.config.js配置文件

module.exports = {
  apps : [{
    name: 'list_page', // 名称
    script: 'src/app.js', // 启动脚本文件
    instances: 1, //实例数
    autorestart: true, // 启用/禁用应用程序崩溃或退出时自动重启
    watch: false, // 是否启用监控模式,默认是false。如果设置成true,当应用程序变动时,pm2会自动重载。这里也可以设置你要监控的文件。
    max_memory_restart: '1G', // 重启时最大的启动内存
  }],
};

3.启动命令

// 启动命令(启动api到后台)
pm2 start ecosystem.config.js
// 显示所有进程状态
pm2 list
// 显示所有进程日志
pm2 logs
// 重启指定的进程
pm2 restart ecosystem.config.js

pm2更多介绍可以借鉴 使用pm2管理node进程

总结

文章虽然有点小长,其实完全学完之后你会发现,里面包含的内容其实不多,主要就是一个列表的增删改查,介绍了node和相关插件的使用,使用express框架可以更加方便的搭建基本的node架构,数据库使用mysql2,sequelize(作为ORM)用来关联项目和数据库,并提供了一些便于前端使用的api对数据库进行操作,最后介绍了pm2,nodejs生成环境管理工具。当然这只是一个node的入门,想要更全面的了解node还是需要更深的学习。最后希望这边文章可以对正在学习node的小伙伴们有点帮助。