koa+mysql实现增删改查-全栈之路(001)
Date: 2020-4-23
以前很少写文章,从今天开始我要挑战一下自己,连续输出100篇技术类文章。这100篇文章我尽量以实战案例为主。
如果你觉得本文还不错,记得关注或者给个 star,你们的赞和 star 是我编写更多更精彩文章的动力!
GitHub 地址
本文重点内容
- 从 0 到 1 集成 node + mysql + ejs 用户管理系统
- 上手 sequelize 不使用sql操作数据库
- 熟悉 MVC 开发模式
成品演示
关键技术点
- 1.1 数据库操作
- 1.2 MVC 模式是什么?
1.1 数据库操作
// 使用 sequelize 代理数据库操作
const { Sequelize, Model, DataTypes } = require('sequelize');
const config = require('./config')
// 配置数据库连接
const sequelise = new Sequelize(
    dbName,
    username, password,
    {
        host: host,
        dialect: 'mysql', // 配置方言
})
class User extends Model {}
// 创建表
User.init({
  username: DataTypes.STRING,
  birthday: DataTypes.DATE
}, { sequelize, modelName: 'user' });
sequelize.sync() // 生成数据表
  .then(() => User.create({ // 插入数据
    username: 'janedoe',
    birthday: new Date(1980, 6, 20)
  }))
  .then(jane => {
    console.log(jane.toJSON());
  });
1.2 MVC模式是什么?
MVC即Model、View、Controller即模型、视图、控制器
Module     - 对象和业务逻辑
View       - 用户界面
Controller - 用来调度 View 和 Model
开始撸代码
第一步 初始化目录
先来初始化下目录结构:
$ mkdir demo_001 && cd demo_001
$ npm init -y
$ npm i -s nodemon better-npm-run
$ npm i -s koa koa-views @koa/router koa-bodyparser
$ npm i -s ejs sequelize mysql2
各个库的版本号为:
@koa/router: 9.0.0, better-npm-run: 0.1.1,ejs: 3.0.2,koa: 2.11.0,koa-views:6.2.1,sequelize:5.21.6,koa-bodyparser:4.3.0,koa-static:5.0.0,mysql2:2.1.0,nodemon:2.0.3
添加 npm scripts 到 package.json:
    "scripts": {
      "start": "npm run dev",
      "dev": "better-npm-run dev",
      "prd": "better-npm-run prd"
    },
    "betterScripts": {
      "dev": {
        "command": "nodemon app.js",
        "env": {
          "NODE_ENV": "development"
        }
      },
      "prd": {
        "env": {
          "NODE_ENV": "production"
        },
        "command": "pm2 start app.js -n demo_001"
      }
    },
第二步 实现 view 层
新建 app.js
// app.js 代码
const Koa = require('koa');
const views = require('koa-views');
const path = require('path');
const bodyparser = require('koa-bodyparser');
const app = new Koa();
app.keys = ['my keys'];
app.use(bodyparser());
app.use(views(path.join(__dirname, './views'), { extension: 'ejs' }));
app.listen(3000, () => {
    console.log('server is running', new Date());
});
让代码跑起来,之后修改代码不用频繁的重启服务。因为开发环境是用 nodemon 托管的
$ npm start
新建 views 目录结构
  demo_001
  ├── router
  │   └── index.js
  ├── views
  │   ├── index.ejs
  │   ├── header.ejs
  │   ├── create.ejs
  │   └── edit.ejs
  └── app.json
  └── package.json
view 层核心代码:
<!-- views/header.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>node + mysql 实现增删改查</title>
</head>
<body>
<!-- views/index.ejs -->
<% include('./header.ejs') %>
    <h1>
        <%= title %>
        <small>实现增删改查</small>
    </h1>
    <a href="/user/create">添加用户</a>
    <style>
        table{
            border-color: #ccc;
        }
        table td, th{
            background: #fff;
        }
    </style>
    <table cellspacing="1"  cellpadding="15" bgcolor="#000"  >
        <thead>
            <tr>
                <th>username</th>
                <th>pwd</th>
                <th>phone</th>
                <th>age</th>
                <th>gender</th>
                <th>操作</th>
            </tr>
        </thead>
        <% for (const user of users) { %>
            <tr>
                <td><%= user.username %></td>
                <td><%= user.pwd %></td>
                <td><%= user.phone %></td>
                <td><%= user.age %></td>
                <td><%= user.gender %></td>
                <td>
                    <a href="/user/edit?id=<%= user.id %>">修改</a>
                    <a href="/user/del/<%= user.id %>">删除</a>
                </td>
            </tr>
        <% } %>
    </table>
</body>
</html>
<!-- views/create.ejs -->
<% include('./header.ejs') %>
    <style>
        label{
            width: 80px;
            display: inline-block;
            text-align: right;
            padding-right: 10px;
        }
    </style>
    <h1>
        <%= title %> <small><a href="/">返回首页</a></small>
    </h1>
    <form action="/user/create" method="POST" >
        <fieldset>
            <label>username</label>
            <input value="" name="username" />
        </fieldset>
        <fieldset>
            <label>pwd</label>
            <input value="" name="pwd" />
        </fieldset>
        <fieldset>
            <label>phone</label>
            <input value="" name="phone" />
        </fieldset>
        <fieldset>
            <label>age</label>
            <input value="" name="age" />
        </fieldset>
        <fieldset>
            <label>gender</label>
            <input value="" name="gender" />
        </fieldset>
        <fieldset>
            <button type="submit">Submit</button>
        </fieldset>
    </form>
</body>
</html>
<!-- views/edit.ejs -->
<% include('./header.ejs') %>
    <style>
        label{
            width: 80px;
            display: inline-block;
            text-align: right;
            padding-right: 10px;
        }
    </style>
    <h1>
        <%= title %> <small><a href="/">返回首页</a></small>
    </h1>
    <form action="/user/edit" method="POST" >
        <input value="<%= user.id %>" name="id" type="hidden" />
        <fieldset>
            <label>username</label>
            <input value="<%= user.username %>" name="username" />
        </fieldset>
        <fieldset>
            <label>pwd</label>
            <input value="<%= user.pwd %>" name="pwd" />
        </fieldset>
        <fieldset>
            <label>phone</label>
            <input value="<%= user.phone %>" name="phone" />
        </fieldset>
        <fieldset>
            <label>age</label>
            <input value="<%= user.age %>" name="age" />
        </fieldset>
        <fieldset>
            <label>gender</label>
            <input value="<%= user.gender %>" name="gender" />
        </fieldset>
        <fieldset>
            <button type="submit">Submit</button>
        </fieldset>
    </form>
</body>
</html>
路由部分核心代码:
const Router = require('@koa/router');
const router = new Router()
// 首页,查询所有用户
router.get('/', async ctx => {
    let users = []
    console.log('查询所有用户')
    await ctx.render('index', { title: 'node + mysql ', users });
});
// 增加
router.get('/user/create', async ctx => {
    await ctx.render('create', { title: '添加用户', method: 'add' })
})
router.post('/user/create', async ctx => {
    console.log('添加用户:',ctx.request)
    ctx.redirect('/')
})
// 修改
router.get('/user/edit', async ctx => {
    const codition = { id: ctx.query.id }
    console.log('查询要修改的用户',codition)
    await ctx.render('edit', { title: '修改用户', method: 'edit', user: {} })
})
router.get('/user/edit', async ctx => {
    console.log('要修改的用户:', ctx.request)
    ctx.redirect('/')
})
// 删除
router.get('/user/del/:id', async ctx => {
    console.log('删除用户id,', ctx.params.id)
    ctx.redirect('/')
})
module.exports = router;
目前为止所有的路由已经准备好了,需要挂载到 koa 实例上
// 修改 app.js
// 引入路由部分
const indexRouter = require('./router/index')
// 挂载到 koa 实例
app.use(indexRouter.routes(), indexRouter.allowedMethods());
到这一步我们已经把页面做好了
打开浏览器输入 http://localhost:3000
到此为止,页面已经可以访问了


第三步 实现 module 层
新建 module 目录结构
  demo_001
  ├── config
  │   ├── dev.js
  │   ├── prd.js
  │   └── index.js
  ├── modules
  │   └── user.js
  ├── router
  ├── views
  ├── db.js
  ├── app.json
  └── package.json
我们先要配置数据库连接:
// config/index.js
if (process.env.NODE_ENV === 'production') {
    module.exports = require('./prd')
} else {
    module.exports = require('./dev')
}
dev 和 prd 分别对应不同环境的数据库连接。这里都写成你自己的数据库地址即可
// config/prd.js, config/dev.js
module.exports = {
    db: {
        // host
        host: '127.0.0.1',
        // 数据库名
        dbName: 'xxxx',
        // 用户名
        username: 'xxxx',
        // 密码
        password: 'xxxx'
    }
}
连接数据库 db.js
// db.js
const Sequelize = require('sequelize');
const config = require('./config')
const { dbName, username, password, host } = config.db;
const sequelise = new Sequelize(
    dbName,
    username, password,
    {
        host: host,
        dialect: 'mysql',
        // 配置连接池
        pool: {
            max: 5,
            min: 0,
            acquire: 30000,
            idle: 10000
        }
})
sequelise
    .authenticate()
    .then(() => {
        console.log('数据库连接成功')
    })
    .catch(err => {
        throw new Error('数据库连接失败', err)
    })
module.exports = sequelise
创建 module
// modules/user.js
const Sequelize = require('sequelize')
const sequelize = require('../db');
const User = sequelize.define('user', {
    username: { type: Sequelize.STRING },
    pwd: { type: Sequelize.STRING, },
    phone: { type: Sequelize.STRING, },
    age: { type: Sequelize.STRING, },
    gender: { type: Sequelize.INTEGER, },
});
module.exports.add = async (data) => await User.create(data)
module.exports.del = async (id) => await User.destroy({ where: { id } })
module.exports.update = async (data) => {
    let newUser = {...data}
    delete newUser['id']
    return await User.update({ ...newUser }, {
        where: { id: data.id }
    })
}
module.exports.find = async (condition) => {
    if (Object.keys(condition).length) {
        return await User.findAll({ where: { ...condition } })
    } else {
        return await User.findAll();
    }
}
第四步 控制层调度
现在要通 修改 过路由,把视图和 module 结合起来。
// router/index.js
// 引入
const UserMudule = require('../modules/user')
// 修改路由:增加
router.post('/user/create', async (ctx) => {
    const {
        username, pwd, phone, age, gender
     } = ctx.request.body
     await UserMudule.add({
        username, pwd, phone, age, gender
     })
    ctx.redirect('/')
})
// 修改路由:首页,查询所有用户
router.get('/', async ctx => {
    let users = await UserMudule.find(ctx.query)
    await ctx.render('index', { title: 'node + mysql ', users });
});
此时已经实现了增加和查询,你可以测试一下这部分功能。
接下来实现修改和删除的代码
// router/index.js
// 修改路由:delete
router.get('/user/del/:id', async ctx => {
    await UserMudule.del(ctx.params.id)
    ctx.redirect('/')
})
// 修改路由:update
router.get('/user/edit', async ctx => {
    const codition = { id: ctx.query.id }
    // 修改前先查询出 User 对象
    let user = await UserMudule.find(codition)
    await ctx.render('edit', { title: '修改用户', method: 'edit', user: user[0] })
})
// 修改路由:update
router.post('/user/edit', async ctx => {
    const {
        username, pwd, phone, age, gender, id
    } = ctx.request.body
    //  接受参数,执行修改
    await UserMudule.update({
    id, username, pwd, phone, age, gender
    })
    ctx.redirect('/')
})
来,测试一下!


总结
到此你已经掌握了简单的 nodejs 服务器开发,下一篇文章我继续带你一步步的上线一个 nodejs 项目
所以,如果你看完真觉得不错,那就给个 star 吧!你的赞和 star 是我编写更多精彩文章的动力GitHub 地址
后记
这篇文章我花了6个小时,写代码,录gif 脖子和胳膊都酸了~~
希望小伙伴们给我一点点打赏,鼓励我写成更多干货文章


koa+mysql实现增删改查-全栈之路(001)的更多相关文章
- Java连接MySQL数据库增删改查通用方法
		版权声明:本文为博主原创文章,未经博主允许不得转载. Java连接MySQL数据库增删改查通用方法 运行环境:eclipse+MySQL 以前我们Java连接MySQL数据库都是一个数据库写一个类,类 ... 
- MySQL数据库(增删改查语句)
		MySQL数据库(增删改查语句)一.登录数据库:----> mysql -uroot -proot;(对应用户名和密码)二.SQL语句: 数据定义语言DDL 用来定义数据库.表.列,关 ... 
- python操作mysql数据库增删改查的dbutils实例
		python操作mysql数据库增删改查的dbutils实例 # 数据库配置文件 # cat gconf.py #encoding=utf-8 import json # json里面的字典不能用单引 ... 
- Asp.Net操作MySql数据库增删改查
		Asp.Net操作MySql数据库增删改查,话不多说直接步入正题.git源码地址:https://git.oschina.net/gxiaopan/NetMySql.git 1.安装MySQL数据库 ... 
- Mysql 的 增删改查
		mysql的增删改查 1:新建数据库 create database 数据库名 [其他选项]; 2:新建数据表 create table students ( id int unsigned not ... 
- MySQL之增删改查之
		MySQL之增删改查 前言:以下是MySQL最基本的增删改查语句,很多IT工作者都必须要会的命令,也是IT行业面试最常考的知识点,由于是入门级基础命令,所有所有操作都建立在单表上,未涉及多表操作. ... 
- MySql之增删改查 · YbWork's Studio
		前提:在进行"增删改查"的操作之前,先建立一个包含数据表student的数据库(具体操作可以见MySQL之最基本命令): 1."增"--添加数据 1.1 为表中 ... 
- 使用MySQL练习增删改查时因为版本问题出现连接错误
		使用MySQL练习增删改查时出现连接错误,错误提示如下: 2020-02-19 19:53:51.088 ERROR 16328 --- [reate-249798694] com.alibaba.d ... 
- (转)mysql的增删改查
		MySQL数据库的增删改查. 1,首先启动mysql数据库的服务,在运行的窗口中输入:net start mysql,这样,就可 以启动mysql数据库的服务,同理,输入net stop mysql, ... 
随机推荐
- Python Tkinter Grid布局管理器详解
			Grid(网格)布局管理器会将控件放置到一个二维的表格里.主控件被分割成一系列的行和列,表格中的每个单元(cell)都可以放置一个控件. 注意:不要试图在一个主窗口中混合使用pack和grid (1) ... 
- vue配置环境踩坑
			Vue 环境配置踩坑 目录 Vue 环境配置踩坑 windows下cnpm -v :无法将"cnpm"项识别为 cmdlet.函数.脚本文件或可运行程序的名称. windows下c ... 
- Android进阶之AIDL的使用详解
			原文首发于微信公众号:jzman-blog,欢迎关注交流! AIDL(Android 接口定义语言),可以使用它定义客户端与服务端进程间通信(IPC)的编程接口,在 Android 中,进程之间无法共 ... 
- git原理,git命令使用详解,github使用 --有此图文并茂原来如此简单
			一.Git分布式控制系统原理:git有三个区,被管理的代码或文件是从:工作区-->暂存区-->本地版本库. 二.GitHub创建线上仓库GitHub是一个面向开源及私有软件项目的托管平台, ... 
- Js,JQuery不同方式绑定的同一事件可以同时触发,互不干扰
			比如,onclick绑定,然后jquery.on("click", function(){})绑定等 
- Python常用模块之模块的使用
			一 模块介绍 1.什么是模块? #常见的场景:一个模块就是一个包含了一组功能的python文件,比如spam.py,模块名为spam,可以通过import spam使用. #在python中,模块 ... 
- 探秘 RocketMQ 消息持久化机制
			我们知道 RocketMQ 是一款高性能.高可靠的分布式消息中间件,高性能和高可靠是很难兼得的.因为要保证高可靠,那么数据就必须持久化到磁盘上,将数据持久化到磁盘,那么可能就不能保证高性能了. Roc ... 
- 值传递:pass by value(按值传递) 和 pass by reference(引用传递)-[all]-[编程原理]
			所有的编程语言,都会讨论值传递问题. 通过一个js示例直观认识 //理解按值传递(pass by value)和按引用传递(pass by reference) //pass by value var ... 
- 【PHP】PHP基本语法
			一.什么是PHP? a) 定义:PHP就是超文本预处理器 b) 超文本:我们前边8天学习的内容其实就是超文本内容 c) 预处理器:相当于牛奶在工厂加工的过程,我们虽然不可见,但是我们 ... 
- Vulnhub JIS-CTF-VulnUpload靶机渗透
			配置问题解决 参考我的这篇文章https://www.cnblogs.com/A1oe/p/12571032.html更改网卡配置文件进行解决. 信息搜集 找到靶机 nmap -sP 192.168. ... 
