使用koa:

koa2是一个类,所以引入koa后,要创建实例化“对象”,才能使用koa内部封装的方法。

设置监听端口:

处理http请求:

1、http请求处理链

A、通过app.use()注册async异步函数

B、每收到一个http请求,koa就会调用通过app.use()注册的async异步函数,并传入ctxnext参数。

2、koa使用异步方法处理请求

async:异步函数

ctx:是由koa传入的封装了request和response的变量

3、next()

用await next()来调用下一个async函数

4、middleware

我们把每个async函数称为middleware

针对不同的url申请调用不同的异步函数:

底层的处理方式,是通过if判断请求的地址来进行区分的

使用if判断非常麻烦,使用koa-router省略这一个步骤

koa-router只能省略掉if判断的部分,最后要使用app.use()去调用koa-router这个异步函数

同理可以处理post请求

用post请求时,会遇到一个问题:post请求通常会发送一个表单,或者JSON,它作为request的body发送

但无论是Node.js提供的原始request对象,还是koa提供的request对象,都不提供解析request的body的功能!

引入另一个middleware ——koa-bodyparser解析request的body

var name = ctx.request.body.name || ''拿到表单的name字段,如果该字段不存在,默认值设置为''

随着需要处理的url越来越多,app.js会显得特别的臃肿

在controller文件中集中描写url:

app.js不再放置url的异步函数处理方式

app.js只用于将所有controller文件夹中的url异步函数,引入,并使用app.use为其注册

引入+注册:就两个函数封装这一些功能

进一步简化app.js

将处理引入与注册url异步函数的方法,作为一个

Controller Middleware

进一步封装到controller.js中,去处理controller文件夹中的url异步函数

const fs = require('fs');

// add url-route in /controllers:

function addMapping(router, mapping) {
for (var url in mapping) {
if (url.startsWith('GET ')) {
var path = url.substring(4);
router.get(path, mapping[url]);
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith('POST ')) {
var path = url.substring(5);
router.post(path, mapping[url]);
console.log(`register URL mapping: POST ${path}`);
} else if (url.startsWith('PUT ')) {
var path = url.substring(4);
router.put(path, mapping[url]);
console.log(`register URL mapping: PUT ${path}`);
} else if (url.startsWith('DELETE ')) {
var path = url.substring(7);
router.del(path, mapping[url]);
console.log(`register URL mapping: DELETE ${path}`);
} else {
console.log(`invalid URL: ${url}`);
}
}
} function addControllers(router, dir) {
fs.readdirSync(__dirname + '/' + dir).filter((f) => {
return f.endsWith('.js');
}).forEach((f) => {
console.log(`process controller: ${f}...`);
let mapping = require(__dirname + '/' + dir + '/' + f);
addMapping(router, mapping);
});
} module.exports = function (dir) {
let
controllers_dir = dir || 'controllers',
router = require('koa-router')();
addControllers(router, controllers_dir);
return router.routes();
};

这样app.js中只需要引入这个middleware,再调用就可以完成url的处理

操作数据库:

ORM技术:Object-Relational Mapping,把关系数据库的表结构映射到js对象上。

ORM框架:Sequelize

数据库配置信息,在使用Sequelize操作MySQL需要放在参数里,告诉函数应该如何做

将其保存在config.js中

var config = {
database: 'test', // 使用哪个数据库
username: 'www', // 用户名
password: 'www', // 口令
host: 'localhost', // 主机名
port: 3306 // 端口号,MySQL默认3306
}; module.exports = config;

1、创建Sequelize对象实例

//引入
const Sequelize = require('sequelize');
const config = require('./config');
//对象实例化
var sequelize = new Sequelize(config.database, config.username, config.password, {
host: config.host,
dialect: 'mysql',
pool: {
max: 5,
min: 0,
idle: 30000
}
});
new Sequelize(database, [username=null], [password=null], [options={}])
//option可选填

2、定义数据模型model让数据库可以创建表

//第一个参数传入名称Pet,默认的表名是Pets
//第二个参数指定列名和数据类型,如果是主键,需要更详细地指定。
//第三个参数是额外的配置,我们传入timestamps: false是为了关闭Sequelize的自动添加timestamp的功能
var Pet = sequelize.define('pet', {
id: {
type: Sequelize.STRING(50),
primaryKey: true
},
name: Sequelize.STRING(100),
gender: Sequelize.BOOLEAN,
birth: Sequelize.STRING(10),
createdAt: Sequelize.BIGINT,
updatedAt: Sequelize.BIGINT,
version: Sequelize.BIGINT
}, {
timestamps: false
});

3、插入数据

promise方式

var now = Date.now();

Pet.create({
id: 'g-' + now,
name: 'Gaffey',
gender: false,
birth: '2007-07-07',
createdAt: now,
updatedAt: now,
version: 0
}).then(function (p) {
console.log('created.' + JSON.stringify(p));
}).catch(function (err) {
console.log('failed: ' + err);
});

await方式

(async () => {
var dog = await Pet.create({
id: 'd-' + now,
name: 'Odie',
gender: false,
birth: '2008-08-08',
createdAt: now,
updatedAt: now,
version: 0
});
console.log('created: ' + JSON.stringify(dog));
})();

4、查询数据

(async () => {
var pets = await Pet.findAll({
where: {
name: 'Gaffey'
}
});
console.log(`find ${pets.length} pets:`);
for (let p of pets) {
console.log(JSON.stringify(p));
}
})();

5、更新数据

如果要更新数据,可以对查询到的实例调用save()方法:

(async () => {
var p = await queryFromSomewhere();
p.gender = true;
p.updatedAt = Date.now();
p.version ++;
await p.save();
})();

6、删除数据

(async () => {
var p = await queryFromSomewhere();
await p.destroy();
})();

直接使用Sequelize虽然可以创建model,但是存在一些问题

混乱,不方便管理,不规范,无法复用

制定一个规范

A、model统一存放在models文件夹中

B、其次,每一个Model必须遵守一套规范:

  1. 统一主键,名称必须是id,类型必须是STRING(50)
  2. 主键可以自己指定,也可以由框架自动生成(如果为null或undefined);
  3. 所有字段默认为NOT NULL,除非显式指定;
  4. 统一timestamp机制,每个Model必须有createdAtupdatedAtversion,分别记录创建时间、修改时间和版本号。其中,createdAtupdatedAtBIGINT存储时间戳,最大的好处是无需处理时区,排序方便。version每次修改时自增。

这一套规范,不需要去记忆,而是通过一个db.js统一Model的定义:

const Sequelize = require('sequelize');

console.log('init sequelize...');

var sequelize = new Sequelize('dbname', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
idle: 10000
}
}); const ID_TYPE = Sequelize.STRING(50); function defineModel(name, attributes) {
var attrs = {};
for (let key in attributes) {
let value = attributes[key];
if (typeof value === 'object' && value['type']) {
value.allowNull = value.allowNull || false;
attrs[key] = value;
} else {
attrs[key] = {
type: value,
allowNull: false
};
}
}
attrs.id = {
type: ID_TYPE,
primaryKey: true
};
attrs.createdAt = {
type: Sequelize.BIGINT,
allowNull: false
};
attrs.updatedAt = {
type: Sequelize.BIGINT,
allowNull: false
};
attrs.version = {
type: Sequelize.BIGINT,
allowNull: false
};
return sequelize.define(name, attrs, {
tableName: name,
timestamps: false,
hooks: {
beforeValidate: function (obj) {
let now = Date.now();
if (obj.isNewRecord) {
if (!obj.id) {
obj.id = generateId();
}
obj.createdAt = now;
obj.updatedAt = now;
obj.version = 0;
} else {
obj.updatedAt = Date.now();
obj.version++;
}
}
}
});
}

怎么调用呢db.js创建model?举个例子!

//引入db.js
const db = require('../db');
//调用db.js中的defineModel,定义并暴露model
module.exports = db.defineModel('users', {
email: {
type: db.STRING(100),
unique: true
},
passwd: db.STRING(100),
name: db.STRING(100),
gender: db.BOOLEAN
});

在使用model进行数据库操作时候,每一次都要导入model,如果同时使用多个model,还要写多条语句去导入,显得特别麻烦

创建一个model.js自动化导入所有的model

const fs = require('fs');
const db = require('./db'); let files = fs.readdirSync(__dirname + '/models'); let js_files = files.filter((f)=>{
return f.endsWith('.js');
}, files); module.exports = {}; for (let f of js_files) {
console.log(`import model from file ${f}...`);
let name = f.substring(0, f.length - 3);
module.exports[name] = require(__dirname + '/models/' + f);
} module.exports.sync = () => {
db.sync();
};

使用model.js

//引入model.js
const model = require('./model');
//掉用导入
let
Pet = model.Pet,
User = model.User; var pet = await Pet.create({ ... });

使用node+mysql进行后端开发的更多相关文章

  1. 招聘前端、Java后端开发、测试、Mysql DBA

    公司介绍: http://www.lagou.com/gongsi/43095.html http://www.yamichu.com 简历发到: zhuye@yamichu.com 招聘职位: JA ...

  2. Python后端开发要求

    关于Python后端开发要求 一.对Python有兴趣,熟悉Python(标准库) 最好阅读过源码 了解Python的优化(熟悉pypy更佳) 二.至少至少一门语言(不说"精通") ...

  3. Node.js 从零开发 web server博客项目[登录]

    web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...

  4. web前端开发和后端开发有什么区别?

    web前端分为网页设计师.网页美工.web前端开发工程师 首先网页设计师是对网页的架构.色彩以及网站的整体页面代码负责 网页美工只针对UI这块儿的东西,比如网站是否做的漂亮 web前端开发工程师是负责 ...

  5. 快速使用node.js进行web开发

    首先关于node.js的学习,这里推荐一本比较好的教程,nodejs web开发指南,该书通俗易懂地将node.js语言特性讲解完之后,又从一个项目角度带领读者使用node.js学习web开发.相信这 ...

  6. 后端开发实践——Spring Boot项目模板

    在我的工作中,我从零开始搭建了不少软件项目,其中包含了基础代码框架和持续集成基础设施等,这些内容在敏捷开发中通常被称为"第0个迭代"要做的事情.但是,当项目运行了一段时间之后再来反 ...

  7. .net core webapi 前后端开发分离后的配置和部署

    背景:现在越来越多的企业都采用了在开发上前后端分离,前后端开发上的分离有很多种,那么今天,我来分享一下项目中得的前后端分离. B/S  Saas 项目:(这个项目可以理解成个人中心,当然不止这么点功能 ...

  8. 微信小程序后端开发(Java语言)笔记

    前言: 因为是第一次真正接触后端开发,从编码到部署服务器到上线,所以做个笔记,也供和我一样的开发小白一些参考. 一.前期工作:开发环境与工具: 1. 编程语言:Java    #笔者还没学PHP,只想 ...

  9. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史

    ---新内容开始--- 番外 大家周一好呀,又是元气满满的一个周一呀!感谢大家在周一这个着急改Bug的黄金时期,抽出时间来看我的博文哈哈哈,时间真快,已经到第十四篇博文了,也很顺顺(跌跌)利利 (撞撞 ...

随机推荐

  1. MySQL主主高可用(keepalive)

    2台新的虚拟机172.16.1.1.172.16.1.2  (配置yum源 ) 安装数据库服务 其中 172.16.1.1.172.16.1.2运行数据库服务并设置数据库管理员从本机登录的密码是xzw ...

  2. python中if语句的使用

    1.对体重标准的判断 #coding:utf-8 height=170weight=65#weight=height-105if weight<height-105: print '您偏瘦!注意 ...

  3. Pycharm 4.5.4 for ubuntu 16.04 下载与安装教程

    首先,我们需要有一台已经安装好 ubuntu 16.04 的操作系统,并且配置好java环境: 方法1: 默认安装 apt-get install default-jdk -y # 安装官网最新的ja ...

  4. hibernate注解--@transient

    @transient:表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性. 如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Bas ...

  5. Disconf使用简单Demo

    创建配置文件 在敲Demo之前,需要在Disconf上创建自己的APP,然后在APP的某个环境下创建配置文件,如下面截图中的流程,这里就简单创建了一个redis.properties,内容是redis ...

  6. javascript事件列表解说

    javascript事件列表解说 事件 浏览器支持 解说 一般事件 onclick IE3.N2 鼠标点击时触发此事件 ondblclick IE4.N4 鼠标双击时触发此事件 onmousedown ...

  7. vue中数组变动更新检测

    Vue 包含两种观察数组的方法分别如下 1.变异方法 顾名思义,变异方法会改变被这些方法调用的原始数组,它们也将会触发视图更新,这些方法如下 push() pop() shift() unshift( ...

  8. Project Euler 15 Lattice paths

    题意:在20×20方阵中从起点出发只允许向右或向下移动到达终点的路径有多少条. 思路:每次只能向右或者向下,总共 40 步,也就是 40 步中每一步都有两种选择,也就是 C (40 , 20) . 为 ...

  9. 用C#调用Windows API向指定窗口发送按键消息

    一.调用Windows API. C#下调用Windows API方法如下: 1.引入命名空间:using System.Runtime.InteropServices; 2.引用需要使用的方法,格式 ...

  10. 【codeforces 799C】Fountains

    [题目链接]:http://codeforces.com/contest/799/problem/C [题意] 你有两种不同的货币; 余额分别为c和d 然后有n种商品; 每种商品只能由两种货币中的某一 ...