Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例
Posted Porschev——积少成多...
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例相关的知识,希望对你有一定的参考价值。
目录
前言
前面一有写到一篇Node.js+Express构建网站简单示例:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp.html
这篇还是用以前的例子, 用Node.js+Koa2构建
Koa: https://github.com/koajs/koa
Koa就不多介绍了,前面也写过Express,同一个团队打造,前面也过express文章,对比着看,自然可以看出些优点!
搭建项目及其它准备工作
CREATE DATABASE IF NOT EXISTS nodesample CHARACTER SET UTF8; USE nodesample; SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS `userinfo`; CREATE TABLE `userinfo` ( `Id` int(11) NOT NULL AUTO_INCREMENT COMMENT \'主键\', `UserName` varchar(64) NOT NULL COMMENT \'用户名\', `UserPass` varchar(64) NOT NULL COMMENT \'用户密码\', PRIMARY KEY (`Id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'用户信息表\';
安装koa-generator: https://github.com/17koa/koa-generator
npm install -g koa-generator
安装成功后下图(版本:1.1.16)
然后创建Koa2项目,安装相关依赖项
cd 工作目录
koa2 项目名
cd 项目目录 && npm install
1.安装使用mysql需要的包
npm install --save mysql
没有使用过的可以看我以前写的相关操作文章:http://www.cnblogs.com/zhongweiv/p/nodejs_mysql.html
2.安装ejs(koa2默认为jade,我习惯使用ejs)
npm install --save ejs
没有使用过的可以看我以前写的相关操作文章:http://www.cnblogs.com/zhongweiv/p/nodejs_express.html
3.安装Session存储相关包(存储到redis)
npm install koa-session https://github.com/koajs/session
npm install --save koa-session
koa-session-redis https://github.com/Chilledheart/koa-session-redis
npm install --save koa-session-redis
1.删除掉创建项目后自带的views和routes下的文件
2.重新规划项目目录,规划后如下
目录规则解释:
1.新增pub目录:主要为了统一存放"数据访问"、"业务逻辑"、"公共方法文件"、"数据库帮助文件"、"配置文件"等
2.新增pub目录下utils目录:主要为了统一存放类似"公共函数文件"、"返回值文件"、"枚举文件"等公共文件
3.新增pub目录下config目录:主要为了统一存放各种类型的配置文件
4.新增pub目录下db目录:主要为了统一存放各种数据库帮助类,比如:"mysql-helper.js"、"mongo-helper.js"等等
5.新增pub目录下model目录:主要为了统一存放各种数据库各表CURD操作
6.新增pub目录下bll目录:主要为了统一存放各种业务逻辑的具体实现
配置文件
从上面的图可以看出,我在pub下新建的config目录下新建了一个config.js
这个config.js中将编写“开发环境”和“发布环境”中所需的配置,代码如下
/** * 配置文件 */ //发布配置 const production = { //服务器端口 SERVER_PORT : 3000, //REDIS配置 REDIS: { host: \'localhost\', port: 6379, password: "abcd", maxAge: 3600000 }, //MYSQL数据库配置 MYSQL: { host: "localhost", user: "root", password: "abcd", port: "3306", database: "nodesample", supportBigNumbers: true, multipleStatements: true, timezone: \'utc\' } } //开发配置 const development = { //服务器端口 SERVER_PORT : 3000, //REDIS配置 REDIS: { host: \'localhost\', port: 6379, password: "abcd", maxAge: 3600000 }, //MYSQL数据库配置 MYSQL: { host: "localhost", user: "root", password: "abcd", port: "3306", database: "nodesample", supportBigNumbers: true, multipleStatements: true, timezone: \'utc\' } } const config = development module.exports = config
规划示例路由,并新建相关文件
示例中将有注册、登录功能,先规划好路由,新建routes、views下的相关需要的文件(如项目目录图中文件),并修改app.js文件
const Koa = require(\'koa\') const app = new Koa() const views = require(\'koa-views\') const json = require(\'koa-json\') const onerror = require(\'koa-onerror\') const bodyparser = require(\'koa-bodyparser\') const logger = require(\'koa-logger\') const config = require(\'./pub/config/config.js\'); const session = require(\'koa-session\'); const RedisStore = require(\'koa2-session-redis\'); const index = require(\'./routes/index\') const reg = require(\'./routes/reg\') const login = require(\'./routes/login\') const logout = require(\'./routes/logout\') // error handler onerror(app) // middlewares app.use(bodyparser({ enableTypes:[\'json\', \'form\', \'text\'] })) app.use(json()) app.use(logger()) app.use(require(\'koa-static\')(__dirname + \'/public\')) app.use(views(__dirname + \'/views\', { extension: \'ejs\' })) // logger app.use(async (ctx, next) => { const start = new Date() await next() const ms = new Date() - start console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) }) app.keys = [\'Porschev\']; const redis_conf = { key: \'Porschev\', maxAge: config.REDIS.maxAge, overwrite: true, httpOnly: true, rolling: false, sign: true, store: new RedisStore({ host: config.REDIS.host, port: config.REDIS.port, password: config.REDIS.password }) }; app.use(session(redis_conf, app)); // routes app.use(index.routes(), index.allowedMethods()) app.use(reg.routes(), reg.allowedMethods()) app.use(login.routes(), login.allowedMethods()) app.use(logout.routes(), logout.allowedMethods()) // error-handling app.on(\'error\', (err, ctx) => { console.error(\'server error\', err, ctx) }); app.listen(config.SERVER_PORT, () => { console.log(`Starting at port ${config.SERVER_PORT}!`) }); module.exports = app
注意看红色标记修改或增加的部分
实现数据访问和业务逻辑相关方法
1.首先编写一个mysql-helper.js方便以连接池的方式进行操作
const config = require(\'./../config/config.js\') const mysql = require("mysql") const pool = mysql.createPool(config.MYSQL) let query = function(sql, args) { return new Promise((resolve, reject) => { pool.getConnection(function(err, connection) { if (err) { resolve(err) } else { connection.query(sql, args, (err, result) => { if (err) { reject(err) } else { resolve(result) } connection.release() }) } }) }) } module.exports = { query }
2.编写数据访问相关方法(model目录下的userinfo.js),如下
const mysqlHelper = require(\'./../db/mysql-helper.js\') const userinfo = { /** * 增加一条数据 * @param {object} args 参数 * @return {object} 结果 */ async add ( args ) { let sql = \'INSERT INTO userinfo(UserName, UserPass) VALUES(?, ?)\' let params = [args.username, args.userpass] let result = await mysqlHelper.query(sql, params) return result }, /** * 根据UserName得到一条数据 * @param {object} args 参数 * @return {object} 结果 */ async getByUserName( args ){ let sql = \'SELECT Id, UserName, UserPass FROM userinfo WHERE UserName = ?\' let params = [args.username] let result = await mysqlHelper.query(sql, params) return result }, /** * 根据UserName得到数量 * @param {object} args 参数 * @return {object} 结果 */ async getCountByUserName( args ){ let sql = \'SELECT COUNT(1) AS UserNum FROM userinfo WHERE UserName = ?\' let params = [args.username] let result = await mysqlHelper.query(sql, params) return result }, } module.exports = userinfo
3.在写业务逻辑之前先规划好返回值(utils目录下retcode.js)
/* * 返回码 */ const RetCode = { SessionExpired: -1, //session过期 Fail: 0, //失败 Success: 1, //成功 ArgsError: 2, //参数错误 UserExisted: 10, //用户已经存在 UsernameOrPasswordError: 11, //用户名或者密码错误 UserNotExist: 12, //用户不存在 }; module.exports = RetCode
4.编写“登录”、“注册”等业务逻辑(bll下userinfo.js)
const usermodel = require(\'./../model/userinfo.js\') const retCode = require(\'./../utils/retcode.js\') const userinfo = { /** * 注册 * @param {object} ctx 上下文 * @return {object} 结果 */ async register ( ctx ) { let form = ctx.request.body const args = { username: form.username, userpass: form.userpass } let result = { code: retCode.Success, data: null } //验证非空 if(!args.username || !args.userpass){ result.code = retCode.ArgsError return result } //根据用户名得到用户数量 let userNumResult = await usermodel.getCountByUserName(args) //用户名已被注册 if(userNumResult[0].UserNum > 0){ result.code = retCode.UserExisted return result } //插入注册数据 let userResult = await usermodel.add(args) if(userResult.insertId <= 0){ result.code = retCode.Fail return result } return result }, /** * 登录 * @param {object} ctx 上下文 * @return {object} 结果 */ async login ( ctx ) { let form = ctx.request.body const args = { username: form.username, userpass: form.userpass } let result = { code: retCode.Success, data: null } //验证非空 if(!args.username || !args.userpass){ result.code = retCode.ArgsError return result } //根据用户名得到用户信息 let userResult = await usermodel.getByUserName(args) //用户不存在 if(userResult.length == 0){ result.code = retCode.UserNotExist return result } //用户名或密码错误 if(userResult[0].UserName != args.username || userResult[0].UserPass != args.userpass){ result.code = retCode.UsernameOrPasswordError return result } //将用户ID存入Session中 ctx.session = {id: userResult[0].Id} return result }, } module.exports = userinfo
注册
1.views目录下reg.ejs
<html> <head> <title>Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例</title> </head> <body> <h1><%= title %></h1> 登录名:<input type="text" id="txtUserName" maxlength="20" /> <br/> <br/> 密码:<input type="password" id="txtUserPwd" maxlength="12" /> <br/> <br/> 密码:<input type="password" id="txtUserRePwd" maxlength="12" /> <br/> <br/> <input type="button" id="btnSub" value="注册" /> </body> </html> <script src="/javascripts/jquery-1.11.2.min.js" type="text/javascript"></script> <script src="/javascripts/md5.js" type="text/javascript"></script> <script type="text/javascript"> $(function(){ $(\'#btnSub\').on(\'click\', function(){ var $txtUserName = $(\'#txtUserName\'), txtUserNameVal = $.trim($txtUserName.val()), $txtUserPwd = $(\'#txtUserPwd\'), txtUserPwdVal = $.trim($txtUserPwd.val()), $txtUserRePwd = $(\'#txtUserRePwd\'), txtUserRePwdVal = $.trim($txtUserRePwd.val()); if(txtUserNameVal.length == 0){ alert(\'用户名不能为空\'); return false; } if(txtUserPwdVal.length == 0){ alert(\'密码不能为空\'); return false; } if(txtUserRePwdVal.length == 0){ alert(\'重复密码不能为空\'); return false; } if(txtUserPwdVal != txtUserRePwdVal){ alert(\'两次密码不一致\'); return false; } $.ajax({ url: \'/reg\', type: \'POST\', dataType: \'json\', data: { username: txtUserNameVal, userpass: hex_md5(txtUserPwdVal) }, beforeSend: function (xhr) {}, success: function (res) { if (res != null && res.code) { var retVal = parseInt(res.code); switch (retVal) { case 2: alert(\'输入有误\'); break; case 0: alert(\'注册失败\'); break; case 1: alert(\'注册成功!\'); location.href = \'/login\' break; case 10: alert(\'用户已注册\'); break; } } else { alert(\'操作失败\'); } }, complete: function (XMLHttpRequest, textStatus) {}, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(\'操作失败\'); } }); }) }); </script>
2.routes目录下reg.js
const router = require(\'koa-router\')() const userBll = require(\'./../pub/bll/userinfo.js\') const title = \'注册\' router.prefix(\'/reg\') router.get(\'/\', async (ctx, next) => { await ctx.render(\'reg\', { title }) }) router.post(\'/\', async (ctx, next) => { let result = await userBll.register(ctx) ctx.body = result; }) module.exports = router
登录
1.views目录下login.ejs
<html> <head> <title>Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例</title> </head> <body> <h1><%= title %></h1> 登录名:<input type="text" id="txtUserName" maxlength="20" /> <br/> <br/> 密码:<input type="password" id="txtUserPwd" maxlength="12" /> <br/> <br/> <input type="button" id="btnSub" value="登录" /> </body> </html> <script src="/javascripts/jquery-1.11.2.min.js" type="text/javascript"></script> <script src="/javascripts/md5.js" type="text/javascript"></script> <script type="text/javascript"> $(function(){ $(\'#btnSub\').on(\'click\', function(){ var $txtUserName = $(\'#txtUserName\'), txtUserNameVal = $.trim($txtUserName.val()), $txtUserPwd = $(\'#txtUserPwd\'), txtUserPwdVal Nodejs学习笔记--- 简介及安装Node.js开发环境