学习笔记(一)搭建node项目

1,526 阅读4分钟

一、运行项目并下载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

Sequelize Docs 中文文档 v4

四、实现简单的登陆

数据进入路由,经过中间件,这里的中间件是为了实现登陆时候,检测同时登陆的最大上限
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…