一、运行项目并下载koa依赖
以下按顺序执行
mkdir myapp //创建文件夹
cd myapp //进入文件夹
npm install koa 下载koa
npm install koa-router 下载koa路由模块

index.js文件内容
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();
router.get('/:name', async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
});
app.use(router.routes());
app.listen(8080);
下载nodemon
使用nodemon运行index.js,nodemon用来避免重复重启项目的繁琐步骤,只要有更改 nodemon会自动重新运行。
npm install nodemon
更改package.json

运行项目
npm run dev
访问http://localhost:8080/123

简单运行起来了!
二、搭建项目基本目录并使用swagger
先上项目目录和项目依赖

先看swagger目录下的router.js文件的内容
import { SwaggerRouter } from 'koa-swagger-decorator';
import path from 'path';
//swagger页面配置
const swaggerRouterOpts = {
title:'前端操作日志',
description: 'swagger doc',
version: '0.0.1',
// swagger地址 我本地的swagger地址http://localhost:8080/index.html,
swaggerHtmlEndpoint: '/index.html',
swaggerJsonEndpoint: `/json.html`,
// [可选] config的附加配置如何显示swagger视图
swaggerConfiguration: {
display: {
defaultModelsExpandDepth: 4,//模型的默认扩展深度(设置为-1将完全隐藏模型)。
defaultModelExpandDepth: 3,//在模型示例部分中模型的默认扩展深度。
docExpansion: 'list', //控制操作和标签的默认扩展设置。
defaultModelRendering: 'model'//控制首次呈现API时如何显示模型。
}
}
}
const swaggerRouter = new SwaggerRouter();
swaggerRouter.swagger(swaggerRouterOpts);
//扫描路由 这里扫描路由需要配合 koa-swagger-decorator的一些api
swaggerRouter.mapDir(path.resolve(__dirname,'../controllers'))
export default swaggerRouter;
swagger目录下的index.js文件的内容,这里主要是把swagger扫描到的路由注册到router上,这几句代码 为什么要单独创建一个文件那?因为这里可以写一些特定的路由操作,这些路由是没在controllers里的
import swaggerRouter from './router';
import Router from 'koa-router';
const router = new Router();
// 服务中间件及路由
router
// swagger-router
.use(swaggerRouter.routes())
export default router;
注册到router上还不行还需要注册到这次服务上
const Koa = require('koa');
import router from "./swagger";
import { restify } from "./middleware/reponseHandle"
// 请求体解析
import bodyParser from 'koa-bodyparser';
async function start() {
const app = new Koa();
app.use(restify());
app.use(bodyParser());
app.use(router.routes()); //注册到服务
app.listen(8080);
}
start()
.catch(err => console.error(err))
我写了一个简单的登陆路由,看看使用swagger是怎么编写路由的
import { request, summary, query, path, body, tags, security, prefix, middlewaresAll } from 'koa-swagger-decorator'
//登陆
// swagger 接口分组
const Tag = tags(['登陆']);
// 接口版本号
const controllerVersion = 'v1';
//路由前缀
@prefix(`/${controllerVersion}/orization`)
export default class LoginController{
@request('post', '/login') //路由和请求方式
@summary('登陆入口') //swagger 链接后面的注释
@Tag
@body({userName:{required:true, type:String},password:{required:true, type:String}})//请求体格式
static async loginEnter(ctx){
ctx.rest('登陆成功')
}
}
写在类上的@prefix装饰器 是给这个类下的所有路由增加前缀,下图是经过上面操作部署好的swagger的页面

注意安装babel依赖
可以在swagger上面测试自己写的接口,贼方便。。。尤其是koa-swagger-decorator提供的装饰器,让代码更容易维护。。
三、建立数据库链接和使用数据基本配置
先配置链接数据库需要的设置,config/application.conf.js
const Sequelize = require('sequelize');
var config = {
database: 'zhangyingjie', // 使用哪个数据库
username: 'root', // 用户名
password: '123456789', // 口令
host: '192.168.10.119', // 主机名
port: 3306 // 端口号,MySQL默认3306
};
var sequelize = new Sequelize(config.database, config.username, config.password, {
host: config.host,
dialect: 'mysql',
pool: {
max: 5,//最大连接数
min: 0,//最小连接数
idle: 30000//连接最大空置时间(毫秒),超时后将释放连接
}
});
function defineModel(name, attributes,options) {
options = Object.assign({
freezeTableName: true, // 不改变表名
timestamps: false, // 不为模型添加createAt 和 updateAt字段
underscorder: true, // 转换列名为下划线命名规则
name: { // 建立关联时表名
singular: name,
plural: name
}
}, options)
return sequelize.define(name, attributes, options);
}
sequelize.defineModel = defineModel
export default sequelize;
上面是链接数据库和数据库模型的一些配置,下面展示数据库映射也就是上图表的实例,js的文件名要和表名一样方便查找。。model/user_info.js
import mysql from "../config/application.conf"
const sequlize = require('sequelize')
export default mysql.defineModel('user_info',{
user_name: {
primaryKey: true,
type:sequlize.STRING //字段类型
},
password: {
type:sequlize.STRING
},
online_number :{
type:sequlize.BOOLEAN
}
})
表的实例必须和数据库字段类型匹配,字段类型可以在下面网址找到,并且有比较全面的sequlize API
四、实现简单的登陆
数据进入路由,经过中间件,这里的中间件是为了实现登陆时候,检测同时登陆的最大上限
import { request, summary, query, path, body, tags, security, prefix, middlewaresAll } from 'koa-swagger-decorator'
import repeatLanding from '../middleware/repeatLanding'
//登陆
// swagger 接口分组
const Tag = tags(['登陆']);
// 接口版本号
const controllerVersion = 'v1';
//路由前缀
@prefix(`/${controllerVersion}/orization`)
// 账号密码正确 并 未超过登陆数量限制 中间件
@middlewaresAll([ repeatLanding ])
export default class LoginController{
@request('post', '/login') //路由和请求方式
@summary('登陆入口') //swagger 链接后面的注释
@Tag
@body({userName:{required:true, type:String},password:{required:true, type:String}})//请求体格式
static async loginEnter(ctx){
ctx.rest('登陆成功')
}
}
下面看中间件的具体实现过程 middleware/repeatLanding.js
import Login from '../service/login.service'
//登陆数量限制
export default async (ctx,next) => {
let {
//账号
userName,
//密码
password
} = ctx.request.body
if(await Login.verifyLoginLimit({userName, password})) throw new Error('登陆设备数量超过限制');
return next();
}
中间件实现过程中,通过service业务层和dao层(数据库的操作)访问了数据库,这个dao层是我在编写过程中发现遗漏层,dao层只负责数据的增删改查。
// service/login.service.js
//登陆上限数量5
const loginLimit = 5;
import { getLoginUser } from '../dao/userInfo.dao'
export default class Login{
//验证登陆上限
static async verifyLoginLimit(data){
//获取当前登陆用户信息
let userInfo = await getLoginUser(data)
if (!userInfo) throw new Error('账号或密码错误');
return userInfo.online_number+1 > loginLimit
}
}
上面提到dao层 用来操作数据库
// dao/userInfo.dao.js
import user_info from '../model/user_info'
export function getLoginUser({userName, password}) {
return user_info.findOne({
where: {
user_name: userName,
password
}
})
}
上面代码中用到很多 throw new Error() 这些错误是怎么返回到前端的那?下面这个中间件文件接受了所有在执行过程中抛出的错误提示
// middleware/reponseHandle.js
export function restify(){
return async (ctx, next) => {
ctx.rest = (data) => {
ctx.response.type = 'application/json';
ctx.response.body = {
result: data,
statusCode: 1000,
message: "OK"
}
}
try{
await next()
}catch(e){
ctx.response.body = {
statusCode: e.statusCode || 43001,
message: e.message || '未知错误'
}
}
}
}
这个中间件是在上面我讲搭建项目基本目录 src/index.js文件中执行的,Koa Context 将 node 的 request 和 response 对象封装到单个对象中,
上面ctx就是 Koa Context,我们这里在ctx封装了一个方法 rest ,用来返回正常的数据,next()是执行下一个中间件,在执行下一个中间件的时候返回
错误 throw出来的错误就会被catch接受并返回给前端展示。
我的数据库结构

swagger测试接口


登陆成功的测试


总结
使用swagger的修饰器,在controllers层添加路由,middleware添加中间件,service添加业务对象,dao层实现数据库操作,model层实现数
据库映射,可以在加一个util工具层,我觉得这种项目结构足以支撑中小型项目了,我打算用node写一套简单的商城,我也是一边学一遍写笔记,一下
篇,写商场的登陆系统。。让我们共同进步!加油!
附赠项目git地址 github.com/zhangyingji…