从零开始搭建一个node+koa2+mysql接口项目

从零开始搭建一个node+koa2+mysql接口项目

  • 初始化项目
    • 1.初始化一个koa2项目
    • 2.安装模块
    • 3.启动服务
    • 4.访问
  • 引入mysql
    • 1.在package中引入mysql依赖
    • 2.新建db.js
    • 3.在app.js中require此模块
    • 4.新建一个utils文件夹,在文件夹中创建一个query.js用来执行sql语句
    • 进行简单的sql查询操作
      • 1.创建app目录下面创建四个文件夹
      • 2.在文件夹下创建js文件
      • 3.bookDao进行sql语句出查询
      • 4.bookimpl调用bookDao
      • 5.controller中调用方法
      • 6.在app.js中添加路由
      • 7.启动项目进行调用
      • 8.一些查询的时候的错误
        • 8.1 :字符串模糊查询出现的错误
        • 8.2:时间格式转换
        • 8.3 简单分页
    • 简单的增删改查
      • 1.新增
      • 2.删除修改
      • 3.查询
        • 3.1get查询
        • 3.2post传参
        • 3.3Restful风格
    • webstorm启动项目
  • 一些比较好用的node插件
    • 1.时间处理moment.js
    • 2.日志处理log4.js
    • 3.数据库处理 knex.js
    • 4.定时任务 cron.js

初始化项目

1.初始化一个koa2项目

$ koa2 koa_mysql_demo

2.安装模块

$ npm install

3.启动服务

$ npm start

4.访问

http://localhost:3000/

创建成功
从零开始搭建一个node+koa2+mysql接口项目_第1张图片

引入mysql

1.在package中引入mysql依赖

  "md5": "^2.2.1",
  "mysql": "^2.14.1",

2.新建db.js

在这里插入图片描述
内容

const database={
    user:'root',
    password:'',
    port:3306,
    host:'localhost',
    database:'publishing_group_2019'
}
module.exports=database

3.在app.js中require此模块

const mysql=require('./config/db.js')

4.新建一个utils文件夹,在文件夹中创建一个query.js用来执行sql语句

在这里插入图片描述

const mysql=require('mysql')
const  mysql_connect=require('../config/db.js')
let pool = mysql.createPool(mysql_connect);
let query = (sql, values) => {

    return new Promise((resolve, reject) => {
        pool.getConnection((err, connection) => {
            if (err) {
                reject(err)
            } else {
                connection.query(sql, values, (err, rows) => {
                    if (err) {
                        reject(err)
                    } else {
                        resolve(rows)
                    }
                    connection.release()
                })
            }
        })
    })
};
module.exports = {
    query
}

进行简单的sql查询操作

1.创建app目录下面创建四个文件夹

从零开始搭建一个node+koa2+mysql接口项目_第2张图片

2.在文件夹下创建js文件

从零开始搭建一个node+koa2+mysql接口项目_第3张图片

3.bookDao进行sql语句出查询

代码如下

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

let getBooklist = name => {
    let _sql = `select * from fa_pg_book where deletetime is  null`;
    return mysql.query(_sql);
};
module.exports = {
    getBooklist : getBooklist
};

4.bookimpl调用bookDao

代码如下

const  bookdao=require('../dao/bookDao')
var getBooklist= async (userId) => {
    var booklist = bookdao.getBooklist();
    return booklist;
}

module.exports = {
    getBooklist : getBooklist
};

5.controller中调用方法

代码如下

let router = require('koa-router')();
let apiModel = require('../service/bookimpl.js');

router.get('/book/list', async (ctx, next) => {
    await Promise.all([
        apiModel.getBooklist(),
    ])
        .then(res => {
            ctx.body = {
                code: 200,
                data: res,
                message: '获取图书列表成功',
            };
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});
module.exports = router

6.在app.js中添加路由

const books = require('./app/controller/bookController')
app.use(books.routes(), books.allowedMethods())

7.启动项目进行调用

http://localhost:3000/book/list

成功
从零开始搭建一个node+koa2+mysql接口项目_第4张图片

8.一些查询的时候的错误

8.1 :字符串模糊查询出现的错误

当模糊查询的时候
如果你在controller中传入参数


apiModel.getBooklist(['图书','推拿']),

在dao中使用的时候

let getBooklist = value=> {
    let _sql = `select * from fa_pg_book where deletetime is  null and (title like  '%?%') or title like '%?%')`;
    return mysql.query(_sql,value);
};

会出现错误如下
从零开始搭建一个node+koa2+mysql接口项目_第5张图片
正确的用法是使用字符串拼接concat

let getBooklist = value=> {
    let _sql = `select * from fa_pg_book where deletetime is  null and (title like  CONCAT('%',?,'%') or title like CONCAT('%',?,'%'))`;
    return mysql.query(_sql,value);
};

8.2:时间格式转换

新建util.js
在这里插入图片描述
内容如下

let util = {
    //时间戳转时间
    getcurrenttimes(date) {
        var time = date;
    // 也可以获取当前的毫秒级时间戳
        var date = new Date(time * 1000);
        var dt = date.getFullYear() + "-" + (date.getMonth() < 10 ? '0' + (date.getMonth()+1) : (date.getMonth()+1)) + "-" + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) ;
    return dt;
},
}
module.exports = util;

在controller中调用

let timetran=require('../util/util')
router.get('/book/list', async (ctx, next) => {
    await Promise.all([
        apiModel.getBooklist(['图书','推拿'])
    ])
        .then(res => {
            for (let i in res[0]) {
            //对时间数据进行处理
                console.log(res[0][i]['createtime'])
                res[0][i]['createtime']= timetran.getcurrenttimes(res[0][i]['createtime'])
            }
            if (res && res.length > 0) {
                let val = res[0];
                ctx.body = {
                    code: 200,
                    data: val,
                    message: '获取图书列表成功',
                }
            }
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});

8.3 简单分页

在dao中

let getBooklistPage = value=> {
    let _sql = `select title,createtime,author from fa_pg_book where deletetime is  null limit ?,?`;
    return mysql.query(_sql,value);
};

在service中

var getBooklistpage= async (value) => {
    var booklist = bookdao.getBooklistPage(value);

    return booklist;
}

在controller中

router.post('/book/listpage', async (ctx, next) => {
    let pageNum=ctx.request.body.pageNum;
    let pageSize=ctx.request.body.pageSize;
    let offset = (pageNum - 1) * pageSize
    await Promise.all([
        apiModel.getBooklistpage([offset,pageSize])
    ])
        .then(res => {
            for (let i in res[0]) {
                res[0][i]['createtime']= util.getcurrenttimes(res[0][i]['createtime'])
            }
            if (res && res.length > 0) {
                let val = res[0];
                ctx.body = {
                    code: 200,
                    data: val,
                    message: '获取图书列表成功',
                }
            }
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});

在postman中调用接口
从零开始搭建一个node+koa2+mysql接口项目_第6张图片
结果如下
从零开始搭建一个node+koa2+mysql接口项目_第7张图片

简单的增删改查

1.新增

在service中

var addbook= async (value) => {
    var addbook = bookdao.addbook(value);

    return addbook;
}
module.exports = {
  
    addbook : addbook
};

在dao中

let addbook = value=> {
    let _sql = `INSERT INTO fa_pg_book(author,title,createtime) VALUES (?,?,?)`;
    return mysql.query(_sql,value);
};


module.exports = {
  
    addbook : addbook
};

在controller中

//新增一条记录
router.post('/book/add1', async (ctx, next) => {
    let author=ctx.request.body.author;
    let title=ctx.request.body.title;
    //当前时间戳
    let createtime =new Date().getTime()/1000;
    await Promise.all([
        apiModel.addbook([author,title,createtime])
    ])
        .then(res => {
                ctx.body = {
                    code: 200,
                    data: res,
                    message: '添加成功',
                }
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});

外部请求
从零开始搭建一个node+koa2+mysql接口项目_第8张图片
返回结果
从零开始搭建一个node+koa2+mysql接口项目_第9张图片

2.删除修改

删除和修改和注册没区别,就dao的sql不同
修改:

let updatebyid = value=> {
    let _sql = `update  fa_pg_book set author=? where id=?`;
    return mysql.query(_sql,value);
};


module.exports = {
    updatebyid : updatebyid,
};

请求

从零开始搭建一个node+koa2+mysql接口项目_第10张图片
删除:

let deletebyid = value=> {
    let _sql = `delete from fa_pg_book where id=?`;
    return mysql.query(_sql,value);
};

module.exports = {
    deletebyid : deletebyid ,
};

从零开始搭建一个node+koa2+mysql接口项目_第11张图片

3.查询

3.1get查询

普通get传参需要在controller中引入url解析

var urls = require('url');

Dao代码如下

let findbyid1 = value=> {
    let _sql = `select title,createtime,author from fa_pg_book where id=?`;
    return mysql.query(_sql,value);
};
module.exports = {
    findbyid1:findbyid1
};

service

var findbyid1= async (value) => {
    var findbyid1 = bookdao.findbyid1(value);

    return findbyid1;
}
module.exports = {
    findbyid1 : findbyid1
};

controller

//get传参根据id查询
router.get('/book/findById', async (ctx, next) => {
    let url=ctx.request.url;
    var params = urls.parse(url, true).query;
    //当前时间戳
    await Promise.all([
       apiModel.findbyid1([params.id])
    ])
        .then(res => {
            ctx.body = {
                code: 200,
                data: res,
                message: '查询成功',
            }
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});

请求路径
从零开始搭建一个node+koa2+mysql接口项目_第12张图片
结果
从零开始搭建一个node+koa2+mysql接口项目_第13张图片

3.2post传参

post传参和之前的post修改提交差不多
controller

//post传参根据id查询
router.post('/book/findById2', async (ctx, next) => {
    let id=ctx.request.body.id;
    //当前时间戳
    await Promise.all([
        apiModel.findbyid1([id])
    ])
        .then(res => {
            ctx.body = {
                code: 200,
                data: res,
                message: '查询成功',
            }
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});

请求从零开始搭建一个node+koa2+mysql接口项目_第14张图片

3.3Restful风格

controller

router.get('/book/findById3/:id', async (ctx, next) => {
    var id=ctx.params.id
    //当前时间戳
    await Promise.all([
        apiModel.findbyid1([id])
    ])
        .then(res => {
            ctx.body = {
                code: 200,
                data: res,
                message: '查询成功',
            }
        })
        .catch(err => {
            ctx.body = {
                code: 500,
                message: err,
            };
        });
});

请求
从零开始搭建一个node+koa2+mysql接口项目_第15张图片

webstorm启动项目

从零开始搭建一个node+koa2+mysql接口项目_第16张图片
点击show npm scripts
弹出npm页面,点击启动
从零开始搭建一个node+koa2+mysql接口项目_第17张图片

一些比较好用的node插件

1.时间处理moment.js

在package.json中引入

"moment": "^2.24.0",

在需要的controller中引入

var moment = require("moment");

最常用的几个方法
1.1将时间戳转换为时间格式

var res = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss');

1.2.将时间格式转换为时间戳

var res = moment(Date.now(), 'YYYY-MM-DD HH:mm:ss').valueOf();

其他方法访问
http://momentjs.cn/

2.日志处理log4.js

koa自身的日志比较简略。可以用log4.js自定义日志的显示
在package.json中引入log4.js

 "log4js": "^5.2.2",

在config中新建logs.js
代码如下

var path = require('path');

//日志根目录
var baseLogPath = path.resolve(__dirname, '../logs')

/*报错输出日志*/
//错误日志目录、文件名、输出完整路径
var errorPath = "/error";
var errorFileName = "error";
var errorLogPath = baseLogPath + errorPath + "/" + errorFileName;

/*请求数据得到响应时输出响应日志*/
//响应日志目录、文件名、输出完整路径
var responsePath = "/response";
var responseFileName = "response";
var responseLogPath = baseLogPath + responsePath + "/" + responseFileName;

/*操作数据库进行增删改等敏感操作记录日志*/
//操作日志目录、文件名、输出完整路径
var handlePath = "/handle";
var handleFileName = "handle";
var handleLogPath = baseLogPath + handlePath + "/" + handleFileName;


module.exports = {
    //日志格式等设置
    appenders:
        {
            "rule-console": {"type": "console"},
            "errorLogger": {
                "type": "dateFile",
                "filename": errorLogPath,
                "pattern": "-yyyy-MM-dd-hh.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
                "maxLogSize": 1000,
                "numBackups": 3,
                "path": errorPath
            },
            "resLogger": {
                "type": "dateFile",
                "filename": responseLogPath,
                "pattern": "-yyyy-MM-dd-hh.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
                "maxLogSize": 1000,
                "numBackups": 3,
                "path": responsePath
            },
            "handleLogger": {
                "type": "dateFile",
                "filename": handleLogPath,
                "pattern": "-yyyy-MM-dd-hh.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
                "maxLogSize": 1000,
                "numBackups": 3,
                "path": responsePath
            },
        },
    //供外部调用的名称和对应设置定义
    categories: {
        "default": {"appenders": ["rule-console"], "level": "all"},
        "resLogger": {"appenders": ["resLogger"], "level": "info"},
        "errorLogger": {"appenders": ["errorLogger"], "level": "error"},
        "handleLogger": {"appenders": ["handleLogger"], "level": "all"},
        "http": {"appenders": ["resLogger"], "level": "info"}
    },
    "baseLogPath": baseLogPath
}

在utils下新建logs.js代码如下

var log4js = require('log4js');
var logsConfig = require('../config/logs.js');
//加载配置文件
log4js.configure(logsConfig);
//调用预先定义的日志名称
var resLogger = log4js.getLogger("resLogger");
var errorLogger = log4js.getLogger("errorLogger");
var handleLogger = log4js.getLogger("handleLogger");
var consoleLogger = log4js.getLogger();

// 格式化日志文本 加上日志头尾和换行方便查看 ==>  普通日志、请求日志、响应日志、操作日志、错误日志
var formatText = {
    info: function(info) {
        var logText = new String();
        //响应日志头信息
        logText += "\n" + "***************info log start ***************" + "\n";
        //响应内容
        logText += "info detail: " + "\n" + JSON.stringify(info) + "\n";
        //响应日志结束信息
        logText += "*************** info log end ***************" + "\n";
        return logText;
    },
    request: function(req, resTime) {
        var logText = new String();
        var method = req.method;
        //访问方法
        logText += "request method: " + method + "\n";
        //请求原始地址
        logText += "request originalUrl:  " + req.originalUrl + "\n";
        //客户端ip
        logText += "request client ip:  " + req.ip + "\n";
        //开始时间
        var startTime;
        //请求参数
        if (method === 'GET') {
            logText += "request query:  " + JSON.stringify(req.query) + "\n";
            // startTime = req.query.requestStartTime;
        } else {
            logText += "request body: " + "\n" + JSON.stringify(req.body) + "\n";
            // startTime = req.body.requestStartTime;
        }
        //服务器响应时间
        logText += "response time: " + resTime + "\n";
        return logText;
    },
    response: function(ctx, resTime) {
        var logText = new String();
        //响应日志开始
        logText += "\n" + "*************** response log start ***************" + "\n";
        //添加请求日志
        logText += formatText.request(ctx.request, resTime);
        //响应状态码
        logText += "response status: " + ctx.status + "\n";
        //响应内容
        logText += "response body: " + "\n" + JSON.stringify(ctx.body) + "\n";
        //响应日志结束
        logText += "*************** response log end ***************" + "\n";
        return logText;
    },
    handle: function(info) {
        var logText = new String();
        //响应日志开始
        logText += "\n" + "***************info log start ***************" + "\n";
        //响应内容
        logText += "handle info detail: " + "\n" + JSON.stringify(info).replace(/\\n/g, "\n") + "\n";
        //响应日志结束
        logText += "*************** info log end ***************" + "\n";
        return logText;
    },
    error: function(ctx, err, resTime) {
        var logText = new String();
        //错误信息开始
        logText += "\n" + "*************** error log start ***************" + "\n";
        //添加请求日志
        logText += formatText.request(ctx.request, resTime);
        //错误名称
        logText += "err name: " + err.name + "\n";
        //错误信息
        logText += "err message: " + err.message + "\n";
        //错误详情
        logText += "err stack: " + err.stack + "\n";
        //错误信息结束
        logText += "*************** error log end ***************" + "\n";
        return logText;
    }
}

module.exports = {
    //封装普通日志
    logInfo: function(info) {
        if (info) {
            consoleLogger.info(formatText.info(info));
        }
    },
    //封装响应日志
    logResponse: function(ctx, resTime) {
        if (ctx) {
            resLogger.info(formatText.response(ctx, resTime));
        }
    },
    //封装操作日志
    logHandle: function(res) {
        if (res) {
            handleLogger.info(formatText.handle(res));
        }
    },
    //封装错误日志
    logError: function(ctx, error, resTime) {
        if (ctx && error) {
            errorLogger.error(formatText.error(ctx, error, resTime));
        }
    }
};

在app.js中调用

const logsUtil = require('./utils/logs.js');
app.use(async (ctx, next) => {
  const start = new Date();					          // 响应开始时间
  let intervals;								              // 响应间隔时间
  try {
    await next();
    intervals = new Date() - start;
    logsUtil.logResponse(ctx, intervals);	  //记录响应日志
  } catch (error) {
    intervals = new Date() - start;
    logsUtil.logError(ctx, error, intervals);//记录异常日志
  }
})

在请求时会生成日志
从零开始搭建一个node+koa2+mysql接口项目_第18张图片

3.数据库处理 knex.js

自己构建原生sql比较麻烦,可以使用knex.js
在package.json中引入knex.js

"knex": "^0.19.5"

在config中新建knex.js
在这里插入图片描述

var mysql = require('knex')({
    client: 'mysql',  connection: {
       host : 'localhost', // IP地址
       user : 'root', // 数据库用户名
       password : '', // 数据库密码
       database : 'publishing_group_2019' ,
        // 连接到的数据库的名字
        }});
module.exports = { mysql }

在dao中调用即可

const  knex=require('../../config/knex')
let findbyid1 = value=> {
    let rs =knex.mysql.select('title', 'createtime','author').from('fa_pg_book').where('id',value);
    return rs;
};

其他方法参照
http://knexjs.org/#Builder

4.定时任务 cron.js

"cron": "^1.7.2",

创建一个js写上简单的定时任务
在这里插入图片描述

var CronJob = require('cron').CronJob;
    //时间戳转时间
        new CronJob('* * * * * *', function() {
            const d = new Date();
            console.log(d);
        }, null, true);

module.exports = CronJob;

然后再app.js里

const  timestask=require('./app/timetask/everday')

启动项目即可,一些其他常用的定时任务

//间隔十秒执行
var CronJob = require('cron').CronJob;
new CronJob('*/10 * * * * *', function() {
    const d = new Date();
	console.log(d);
}, null, true);
//每分钟第十秒执行
var CronJob = require('cron').CronJob;
new CronJob('10 * * * * *', function() {
    const d = new Date();
	console.log(d);
}, null, true);

在线Cron表达式生成器
http://cron.qqe2.com/

你可能感兴趣的:(node)