koa2中間件分離與數據層搭建
接着上一篇《Js全棧開發之koa2視圖層搭建》來繼續學習koa2,上一篇着重彙總講解了使用模板和靜態包拆分出視圖層的一些具體步驟,而沒有講解模型層,本篇將總結數據庫的訪問及模型層的搭建,以及從koa2項目中拆分出中間件的具體步驟。這裏的模型層採用的ORM框架是Sequelize,數據庫爲MySQL。
文章目錄
1. 提取中間件層
爲方便維護,將中間件層從app.js入口文件中提取出來。新增middleware中間件目錄,增加midsend發送json串的中間件。
1.2 項目結構
├── controller/
│ ├── home.js
├── service/
│ ├── home.js
├── middleware/
│ ├── midsend/
│ ├──── index.js
│ ├── index.js
├── views/
│ ├── common/
│ ├──── header.html
│ ├──── footer.html
│ ├──── layout.html
│ ├──── layout-home.html
│ ├── home/
│ ├──── index.html
│ ├──── login.html
│ ├──── success.html
├── public/
│ ├── home/
│ ├──── main.css
├── app.js
├── router.js
├── package.json
1.3 midsend中間件
index.js 將響應返回類型改爲json格式的字符串,且將對象json序列化
module.exports = () => {
function render(json) {
this.set("Content-Type", "application/json")
this.body = JSON.stringify(json)
}
return async (ctx, next) => {
ctx.send = render.bind(ctx)
await next()
}
}
使用misend
await ctx.send({
status: 'success',
data:[
{
name : 'dahlin',
age:'18'
},{
name : 'leon',
age:'22'
}
,{
name : 'ada',
age:'16'
}
]
})
1.4 中間件層拆分
index.js 將中間件引入的部分代碼從app.js中拆分出來
const path = require('path')
const bodyParser = require('koa-bodyparser')
const nunjucks = require('koa-nunjucks-2')
const staticFiles = require('koa-static')
const miSend = require('./midsend')
module.exports = (app) => {
app.use(staticFiles(path.resolve(__dirname, "../public")))
app.use(nunjucks({
ext: 'html',
path: path.join(__dirname, '../views'),
nunjucksConfig: {
trimBlocks: true
}
}));
app.use(bodyParser())
app.use(miSend())
// 最後攔截異常信息
app.use(async (ctx,next) =>{
try {
await next();
} catch (ex) {
var jsonData={
status:-1,
message:ex.message
}
await ctx.send(jsonData);
}
})
}
1.5 app.js入口處理
const Koa = require('koa')
const app = new Koa()
const router = require('./router')
const middleware = require('./middleware')
middleware(app)
router(app)
app.listen(3000, () => {
console.log('server is running at http://localhost:3000')
})
其他部分代碼參見上一篇博文。
2. ORM框架Sequelize使用
使用安裝Sequelize前,需要安裝mysql驅動包和Sequelize框架
2.1 npm安裝Sequelize
npm install mysql2 -save
npm install sequelize -save
2.2 orm數據層結構
增加db數據目錄及子目錄api和models。api目錄裏存放的是操作數據庫的增刪改查方法,models中存放的是數據庫的表模型腳本,用於生成表同步表,同步數據庫數據用。dbConn.js是數據庫連接方法,syncTable.js是同步數據庫腳本。
├── controller/
│ ├── home.js
│ ├── customer.js
├── db/
│ ├── api/
│ ├──── customer.js
│ ├── models/
│ ├──── customer.js
│ ├── dbConn.js
│ ├── syncTable.js
├── service/
│ ├── home.js
├── middleware/
│ ├── midsend/
│ ├──── index.js
│ ├── index.js
├── views/
│ ├── common/
│ ├──── header.html
│ ├──── footer.html
│ ├──── layout.html
│ ├──── layout-home.html
│ ├── home/
│ ├──── index.html
│ ├──── login.html
│ ├──── success.html
├── public/
│ ├── home/
│ ├──── main.css
├── app.js
├── router.js
├── package.json
2.3 dbConn.js數據庫連接腳本
var Sequelize = require('sequelize');
// 數據庫配置文件
var sqlConfig = {
host: "xxx.xxx.xxx.xxx",
user: "root",
password: "xxxxx*",
database: "koa2learn"
};
var sequelize = new Sequelize(sqlConfig.database, sqlConfig.user, sqlConfig.password, {
host: sqlConfig.host,
dialect: 'mysql',
pool: {
max: 10,
min: 0,
idle: 10000
}
});
module.exports = sequelize;
2.4 models/customer.js模型
const Sequelize = require('sequelize');
const sequenlizeObj = require('../dbConn.js');
const Customer = sequenlizeObj.define('customer',{
id:{
type: Sequelize.BIGINT(11),
primaryKey: true,
allowNull: false,
unique: true,
autoIncrement: true
},
name:{
type:Sequelize.STRING(20),
allowNull:false
},
sex:{
type: Sequelize.ENUM(['男','女']),
allowNull:false
},
address:{
type:Sequelize.STRING(50)
},
phone:{
type:Sequelize.STRING(20),
allowNull:true
},
email:{
type: Sequelize.STRING(20),
allowNull:false
},
country:{
type:Sequelize.STRING(20)
},
city:{
type:Sequelize.STRING(30)
}
},{
timestamps:false,
tableName: 'customer'
});
module.exports = Customer;
2.5 syncTable.js數據同步腳本
const sequenlizeConn = require('./dbConn.js');
var customer = require('./models/customer.js');
sequenlizeConn.authenticate().then(() => {
console.log('Connection has been established successfully.');
// 同步表結構
customer.sync({
force: true // 強制同步,先刪除表,然後新建
}).then(()=>{
// 添加一條基礎數據
return customer.create({
name:'dahlin',
sex:'男',
email:'[email protected]',
phone:'13588888888',
country: '中國',
city:"北京",
address:'盧溝橋'
});
});
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
使用時需要在終端中執行node命令
node ./db/syncTable.js
執行結果如圖,數據和表將自動同步到數據庫中。
2.6 api/customer.js數據操作方法
const Customer = require('../models/customer');
const { Op } = require('sequelize');
module.exports = {
getAllCustomers : async()=>{
return Customer.findAndCountAll({
attributes: ['id','name','sex','address','phone','email','country','city'],
order:[
['id', 'DESC']
]
});
},
getCustomerById : async(id)=>{
return Customer.findAll({
where: {
id: `${id}`
}
})
},
getCustomerByName: async(name)=>{
return Customer.findAll({
where: {
name: {
[Op.like]: `${name}`
}
}
})
},
updateCustomer: async(id,data)=> {
var item = await Customer.findAll({
where: {
id: `${id}`
}
});
if(item!=undefined){
return Customer.update(data, {where: {id: id}})
}else{
throw new Error('the customer is not exist!');
}
},
createCustomer: async(data)=>{
return Customer.create(data)
},
deleteCustomer: async(id)=>{
var item = await Customer.findAll({
where: {
id: `${id}`
}
});
if(item!=undefined){
return Customer.destroy({where: {id: id}})
}else{
throw new Error('the customer is not exist!');
}
}
}
2.7 控制器層customer.js方法
const customerModel = require('../db/api/customer');
module.exports = {
getAllCustomers: async(ctx, next) => {
const customerobjs = await customerModel.getAllCustomers();
var jsonData={
status:0,
data:customerobjs
}
await ctx.send(jsonData);
},
getCustomerById: async(ctx, next) => {
const customerobjs = await customerModel.getCustomerById(ctx.params.id);
var jsonData={
status:0,
data:customerobjs
}
await ctx.send(jsonData);
},
getCustomerByName: async(ctx, next) => {
const customerobjs = await customerModel.getCustomerByName(ctx.params.name);
var jsonData={
status:0,
data:customerobjs
}
await ctx.send(jsonData);
},
updateCustomer: async(ctx, next) => {
const customerobjs = await customerModel.updateCustomer(ctx.params.id,ctx.request.body)
var jsonData={
status:0,
data:customerobjs
}
ctx.send(jsonData);
},
createCustomer: async(ctx, next) => {
const customerobj =ctx.request.body;
const resultObj = await customerModel.createCustomer(customerobj);
var jsonData={
status:0,
data:resultObj
}
await ctx.send(jsonData);
},
deleteCustomer: async(ctx, next) => {
const customerobjs = await customerModel.deleteCustomer(ctx.params.id);
var jsonData={
status:0,
data:customerobjs
}
await ctx.send(jsonData);
}
}
2.8 路由層中間件
const router = require('koa-router')()
const HomeController = require('./controller/home')
const CustomerController = require('./controller/customer')
module.exports = (app) => {
// http://localhost:3000/customer/1
router.get('/customer/:id', CustomerController.getCustomerById)
// http://localhost:3000/customer/name/dahlin
router.get('/customer/name/:name', CustomerController.getCustomerByName)
// 增加數據方法
router.post('/customer', CustomerController.createCustomer)
// 修改數據方法
router.put('/customer/:id', CustomerController.updateCustomer)
// 刪除數據方法
router.delete('/customer/:id', CustomerController.deleteCustomer)
app.use(router.routes())
.use(router.allowedMethods())
}
- 執行增加數據
- 執行查詢所有數據
- 執行修改數據