随着Node.js的日益火热,各种框架开始层出不穷的涌现出来,Node.js也开始逐渐的被应用到处理服务端请求的场景中。搭建Web项目的框架也随之开始出现——express、koa、koa2、egg等,当然要了解其好坏还是要自己去啃源码的。本文将不会涉及到源码,只是带领初学者简单了解下Koa2的基本使用,欢迎大家在评论中互相交流学习。
注意:koa2使用了ES7的语法,所以使用时请升级Node版本到最新。 

  了解更详细的源码信息可以到git上的koajs/koa去了解。

1.项目目录结构

2. 代码逻辑解析

2.1. 包结构文件

{
"name": "weixin-node-koa",
"version": "1.0.0",
"description": "node.js with koa2",
"private": true,
"dependencies": {
"koa": "^2.0.0",
"koa-router": "^7.0.0",
"mysql":"2.13.0"
},
"scripts": {
"start": "node app.js"
},
"engines": {
"node": ">=6.0.0"
},
"author": "Fly",
"license": "CENTERM"
}

2.2. 启动入口文件

app.js

const Koa = require('koa');
const app = new Koa();
const router2controller = require('./app/router2controller.js');
const config = require('./config/config.local.js'); app.use(router2controller());
app.listen(config.port);
console.log("Server started and listen on port " + config.port);

如果请求的报文体是XML格式,可以添加下面的代码自动解析报文(注意引用koa-xxx的版本要与koa2对应)

const Koa = require('koa');
const app = new Koa();
const router2controller = require('./app/router2controller.js');
const config = require('./config/config.local.js'); //start接收到的xml数据请求单独解析存储
const xmlParser = require('koa-xml-body');
app.use(xmlParser()).use((ctx,next) => {
ctx.data = ctx.request.body;
return next();
});
//end app.use(router2controller());
app.listen(config.port);
console.log("Server started and listen on port " + config.port);

从代码看到引入了一个router2controller.js的文件,这个文件是完成前端请求到具体处理方法的路由过程

2.3. 路由器文件

router2controller.js,该类将会自动扫描controller文件夹中的文件来加载请求映射,不需要挨个请求单独配置

koa-router原生提供方法如下:

router
.get('/', async (ctx,next) => {
this.body = 'Hello World!';
})
.post('/users', async (ctx,next) => {
//TODO
})
.put('/users/:id', async (ctx,next) => {
//TODO
})
.del('/users/:id', async (ctx,next) => {
//TODO
});

自动扫描controller包实现方法如下

const fs = require('fs');
const router = require('koa-router')(); 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) {
var controllersDir = dir || 'controller';
addControllers(router, controllersDir);
return router.routes();
};

2.4. 控制器

userController.js,***Controller.js是用来处理具体请求信息以及返回数据的,userController.js中处理了GET请求获取用户信息,POST请求保存用户信息

const userService = require('./../service/userService.js');

var getUserinfo = (ctx, next) => {
let query = ctx.query;
let userId = query.id;
let userInfo = userService.getUserById(userId); let html = '<html><body>'
+ '<div> userinfo:&nbsp;' + userInfo + '</div>'
+ '</body></html>';
ctx.response.type ='text/html';
ctx.response.body = html;
}; var saveUserinfo = (ctx, next) => {
const requestString = ctx.data;
//TODO数据处理
Console.log(requestString);
}; module.exports = {
'GET /getUserinfo': getUserinfo,
'POST /saveUserinfo': saveUserinfo
};

2.5. 数据处理

userService.js,处理封装从***Dao.js获取到的数据返回给Controller

const userDao = require('./../dao/userDao.js');

var getUserById = async (userId) => {
var users = userDao.getUserById(userId);
var responseContent = '';
for(let user of users) {
reaponseContent += '姓名:' + user.name + '&nbsp;|';
reaponseContent += '年龄:' + user.age + '&nbsp;|';
reaponseContent += '身高:' + user.height + '<br />';
}
return responseContent;
} module.exports = {
getUserById : getUserById
};

2.6. 数据获取

userDao.js,通过请求传入参数来获取user数据

const mysql = require('./../utils/mysqlUtil.js');

var getUserById = async (userId) => {
let mysqlOptions = {
sql : 'select * from table_user where user_id = ?',
args : [userId]
}; var users = await mysql.execQuery(mysqlOptions);
if(users.length == 0) {
return null;
} else {
return users;
}
}; module.exports = {
getUserById : getUserById
};

2.7. 数据库操作

mysqlUtil.js,包含了数据库连接池控制,连接建立、释放管理,执行Dao发起的数据库操作请求

const mysql = require('mysql');
const config = require('./../../config/config.local.js'); var connectionPool = mysql.createPool({
'host' : config.database.host,
'port':config.database.port,
'user' : config.database.user,
'password' : config.database.password,
'database' : config.database.database,
'charset': config.database.charset,
'connectionLimit': config.database.connectionLimit,
'supportBigNumbers': true,
'bigNumberStrings': true
}); var release = connection => {
connection.end(function(error) {
if(error) {
console.log('Connection closed failed.');
} else {
console.log('Connection closed succeeded.');
}
});
}; var execQuery = sqlOptions => {
var results = new Promise((resolve, reject) => {
connectionPool.getConnection((error,connection) => {
if(error) {
console.log("Get connection from mysql pool failed !");
throw error;
} var sql = sqlOptions['sql'];
var args = sqlOptions['args']; if(!args) {
var query = connection.query(sql, (error, results) => {
if(error) {
console.log('Execute query error !');
throw error;
} resolve(results);
});
} else {
var query = connection.query(sql, args, function(error, results) {
if(error) {
console.log('Execute query error !');
throw error;
} resolve(results);
});
} connection.release(function(error) {
if(error) {
console.log('Mysql connection close failed !');
throw error;
}
});
});
}).then(function (chunk) {
return chunk;
}); return results;
}; module.exports = {
release : release,
execQuery : execQuery
}

此实例我并没有整理并在本机运行过,但这个包结构的思路还是值得学习的,整个实例的代码详见http://bijian1013.iteye.com/blog/2425085

文章来源:https://blog.csdn.net/ererfei/article/details/68060551

使用Koa2搭建web项目的更多相关文章

  1. 【maven】 在 MyEcplise上使用maven搭建Web项目

    二.在My Ecplise上使用Maven搭建Web项目 1.新建一个maven项目   2.create一个简单的骨架 3.就像在ecplise中一样设置项目的以下配置   4.新创建的项目结构如下 ...

  2. Spring-Boot快速搭建web项目详细总结

    最近在学习Spring Boot 相关的技术,刚接触就有种相见恨晚的感觉,因为用spring boot进行项目的搭建是在太方便了,我们往往只需要很简单的几步,便可完成一个spring MVC项目的搭建 ...

  3. 如何使用maven搭建web项目

    博客园注册了有二十多天了,还没有写过博客,今天就发一篇,也便于后面查找笔记. 我个人已经做了几年的java web开发了,由于所在的公司是业务型公司,用的都是一些老旧的稳定技术,很少接触到稍微新点的内 ...

  4. Spring Boot入门-快速搭建web项目

    Spring Boot 概述: Spring Boot makes it easy to create stand-alone, production-grade Spring based Appli ...

  5. Spring Boot搭建Web项目常用功能

    搭建WEB项目过程中,哪些点需要注意: 1.技术选型: 前端:freemarker.vue 后端:spring boot.spring mvc 2.如何包装返回统一结构结果数据? 首先要弄清楚为什么要 ...

  6. springBoot 搭建web项目(前后端分离,附项目源代码地址)

    springBoot 搭建web项目(前后端分离,附项目源代码地址)   概述 该项目包含springBoot-example-ui 和 springBoot-example,分别为前端与后端,前后端 ...

  7. 使用idea+springboot+Mybatis搭建web项目

    使用idea+springboot+Mybatis搭建web项目 springboot的优势之一就是快速搭建项目,省去了自己导入jar包和配置xml的时间,使用非常方便. 1.创建项目project, ...

  8. hbase搭建web项目 报500错误 HTTP Status 500 - Unable to compile class for JSP

    在昨天,用hbase做后台搭建web项目时,前边的进行的非常顺利,当运行时便 报错了,截图如下: 这是直接在jsp中接收参数报的错误,如果在servlet中,同样也是报500的错误,虽然显示的不太一样 ...

  9. (第01节)IDEA快速搭建web项目

    在配置好环境,熟悉了IDEA的基本操作后,就要开始搭建WEB项目了: File——>new——>project——>然后选择Maven 点击Create from archetype ...

随机推荐

  1. 转:getContextPath、getServletPath、getRequestURI的区别

    假定你的web application 名称为news,你在浏览器中输入请求路径: http://localhost:8080/news/main/list.jsp 则执行下面向行代码后打印出如下结果 ...

  2. 自定义Asp.net core——日志记录

    本文我将演示如何定制日志记录.默认的日志记录仅仅向控制台或者debug窗口输出日志,这样可以满足一些情况,但是你可能还需要把日志记录到一个磁盘文件或者数据库,或者你想为记录额外的信息.这样的场景你就需 ...

  3. 《ASP.NET MVC 5 破境之道》:第一境 ASP.Net MVC5项目初探 — 第二节:MVC5项目结构

    第一境 ASP.Net MVC5项目初探 — 第二节:MVC5项目结构 接下来,我们来看看,VS为我们自动创建的项目,是什么样子的? 可以通过菜单中[View]->[Solution Explo ...

  4. pageadmin CMS网站制作教程:栏目单页内容如何修改

    pageadmin CMS网站制作教程:栏目单页内容如何修改 一般情况下,如公司介绍,联系方式等介绍内页面都属于单页,单页内容可以直接在栏目设置界面进行修改,如下 1.对栏目单页内容进行设置,登录后台 ...

  5. 如何使用socket进行java网络编程(五)

    本篇记录: 1.再谈readLine()方法 2.什么是真正的长连接 最近又参与了一个socket的项目,又遇到了老生常谈的readLine()问题:对方通过其vb程序向我方socketServer程 ...

  6. 914. X of a Kind in a Deck of Cards

    In a deck of cards, each card has an integer written on it. Return true if and only if you can choos ...

  7. 《Python绝技:运用Python成为顶级黑客》 Python实用小工具

    1.实现简单探测 使用socket模块,connect()方法建立与指定IP和端口的网络连接:revc(1024)方法将读取套接字中接下来的1024B数据 mport socket import sy ...

  8. Android逆向进阶——让你自由自在脱壳的热身运动(dex篇)

    本文作者:HAI_ 0×00 前言 来看看我们今天的主题. 让你自由自在脱壳的热身运动. 现在很多第厂家都是使用第三方的加固方式来进行加固的.或者使用自己的加固方式进行加固. 那么我们必不可少的就是脱 ...

  9. java实现fp-growth算法

    本文参考韩家炜<数据挖掘-概念与技术>一书第六章,前提条件要理解 apriori算法. 另外一篇写得较好的文章在此推荐: http://hi.baidu.com/nefzpohtpndho ...

  10. C的Define

    #define Conn(x,y) x##y  //表示x连接y #define ToChar(x) #@x //给x加上单引号 #define ToString(x) #x  //给x加双引号 #d ...