目录

前言

  前面一有写到一篇Node.js+Express构建网站简单示例:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp.html

  这篇还是用以前的例子, 用Node.js+Koa2构建

  Koa:   https://github.com/koajs/koa

      http://koa.bootcss.com  (中文)

  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='用户信息表';

创建Koa2项目

安装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

retcode.js

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>

reg.ejs

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 = $.trim($txtUserPwd.val()); if(txtUserNameVal.length == 0){
alert('用户名不能为空');
return false;
} if(txtUserPwdVal.length == 0){
alert('密码不能为空');
return false;
} $.ajax({
url: '/login',
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 = '/'
break;
case 11:
alert('用户名或者密码错误');
break;
case 12:
alert('用户不存在');
break;
}
}
else {
alert('操作失败');
} },
complete: function (XMLHttpRequest, textStatus) {},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('操作失败');
}
});
})
}); </script>

login.ejs

2.routes目录下login.js

const router = require('koa-router')()
const userBll = require('./../pub/bll/userinfo.js')
const title = '登录' router.prefix('/login') router.get('/', async (ctx, next) => {
await ctx.render('login', { title })
}) router.post('/', async (ctx, next) => { let result = await userBll.login(ctx); ctx.body = result; }) module.exports = router

首页

1.views目录下index.ejs

<html>
<head>
<title>Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例</title>
</head>
<body>
<h1><%= title %></h1> <% if(id != null) {%>
<h3>登录用户ID:<%= id %> <a id="btnLogOut" href="javascript:void(0);">安全退出</a></h3>
<% } %>
</body>
</html> <script src="/javascripts/jquery-1.11.2.min.js" type="text/javascript"></script> <script type="text/javascript">
$(function(){
$('#btnLogOut').on('click', function(){ if(!confirm('确认要退出吗?')){
return;
} $.ajax({
url: '/logout',
type: 'POST',
dataType: 'json',
data: {},
beforeSend: function (xhr) {},
success: function (res) {
if (res != null && res.code) { var retVal = parseInt(res.code); switch (retVal) {
case 0:
alert('失败');
break;
case 1:
alert('成功!');
location.href = '/login'
break;
}
}
else {
alert('操作失败');
} },
complete: function (XMLHttpRequest, textStatus) {},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('操作失败');
}
});
})
}); </script>

index.ejs

2.routes目录下index.js

const router = require('koa-router')()
const title = '首页' router.get('/', async (ctx, next) => {
//判断登录
if(!ctx.session || !ctx.session.id){
await ctx.redirect('/login')
}else{
const id = ctx.session.id;
await ctx.render('index', { title, id })
}
}) module.exports = router

index.js文件中实现如果不存在session则跳回登录页

安全退出

1.routes目录下logout.js

const router = require('koa-router')()
const retCode = require('./../pub/utils/retcode.js') router.prefix('/logout') router.get('/', async (ctx, next) => {
await ctx.render('logout', {})
}) router.post('/', async (ctx, next) => { ctx.session = null; let result = {
code: retCode.Success,
data: null
} ctx.body = result; }) module.exports = router

写在之后

没有去说一些细节API,写这篇主要可以对比 Nodejs学习笔记(七)--- Node.js + Express 构建网站简单示例 来看,完全是一亲的示例,只是这次用的Koa2,方便大家看看Koa2和express写出来的不同

总的来说Koa2还是比较好上手,async、await这个对于有C#语言基础的来说也比较亲切,不用二次理解

可以对比一下express时的各种嵌套回调写法,Koa2写好更优雅、更易阅读

 示例有限,其它操作通过官网查找API或github找一些组件来动手试,比如最常用的一些功能:操作cookies、上传文件、session存储到其它介质等

 参考资料: https://koa.bootcss.com/

 老规矩不放源码,虽然是示例结构,但是尽量按照平常做项目的想法去实现的,有兴趣的动手去搭项目做才会理解一些思路,代码都放在文章中了,有问题留言^_^!

Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例的更多相关文章

  1. [转]Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例

    本文转自:https://www.cnblogs.com/zhongweiv/p/nodejs_koa2_webapp.html 目录 前言 搭建项目及其它准备工作 创建数据库 创建Koa2项目 安装 ...

  2. Nodejs学习笔记(十五)—Node.js + Koa2 构建网站简单示例

    前言 前面一有写到一篇Node.js+Express构建网站简单示例:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp.html 这篇还 ...

  3. Nodejs学习笔记(七)--- Node.js + Express 构建网站简单示例

    目录 前言 新建项目.建立数据库以及其它准备工作 新建express + ejs 项目:sampleEjs 创建数据库 修改package.json文件,安装session和mysql模块 样式和JQ ...

  4. Nodejs学习笔记(七)—Node.js + Express 构建网站简单示例

    前言 上一篇学习了一些构建网站会用到的一些知识点:https://www.cnblogs.com/flyingeagle/p/9192936.html 这一篇主要结合前面讲到的知识,去构建一个较为完整 ...

  5. Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识

    目录 前言 新建express项目并自定义路由规则 如何提取页面中的公共部分? 如何提交表单并接收参数? GET 方式 POST 方式 如何字符串加密? 如何使用session? 如何使用cookie ...

  6. Nodejs学习笔记(六)—Node.js + Express 构建网站预备知识

    前言 前面经过五篇Node.js的学习,基本可以开始动手构建一个网站应用了,先用这一篇了解一些构建网站的知识! 主要是些基础的东西... 如何去创建路由规则.如何去提交表单并接收表单项的值.如何去给密 ...

  7. python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...

  8. Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs

    目录 前言 Express简介和安装 运行第一个基于express框架的Web 模版引擎 ejs express项目结构 express项目分析 app.set(name,value) app.use ...

  9. Nodejs学习笔记(五)—Express安装入门与模版引擎ejs

    前言 前面也学习了一些Node.js的基本入门知道,现在开始进入Web开发的部分: Node.js提供了http模块,这个模块中提供了一些底层接口,可以直接使用,但是直接开发网站那还是太累了,所以ht ...

随机推荐

  1. ubuntu环境下lnmp环境搭建(1)之Mysql

    1. vm下安装Ubuntu 1)下载镜像ubuntu-15.04-desktop-amd64.iso http://yunpan.cn/cF5dwV6zw33ef 访问密码 ecba(个人分享在36 ...

  2. 平板不能设置代理的情况下利用随身wifi进行http代理访问

    需求来源:平板或手机是个封闭系统无法给wifi设置代理,需要利用filllder进行抓包,内容篡改等实验 拥有硬件资源:PC机器 + 小米随身wifi 方案1: NtBind Dns + Nginx ...

  3. Akka 的Actor

    从第一篇Akka笔记的介绍中,我们是从很高的高度去观察Akka工具箱中的Actors.在这篇笔记的第二篇,我们会看一下Actors中的消息部分.而且延续上一次的例子,我们还会使用同样的学生与老师的例子 ...

  4. Excel导出插件

    前言 一个游戏通常需要10多个Excel表格或者更多来配置,一般会通过导出csv格式读取配置. 本文提供导出Excel直接生成c#文件,对应数据直接生成结构体和数组,方便开发排错和简化重复写每个表格的 ...

  5. C语言第一次实验报告————PTA实验1.2.3内容

    一.PTA实验作业 题目1.温度转换 本题要求编写程序,计算华氏温度100°F对应的摄氏温度.计算公式:C=5×(F−32)/9,式中:C表示摄氏温度,F表示华氏温度,输出数据要求为整型. 1.实验代 ...

  6. 使用docker 解决一个小问题,你也可能用的到

    以前一直觉得docker是运维用的工具,或者devops 用的工具,一般人应该用不上,直到最近发现docker 还有另外一个妙用,不管是什么语言. 这几天开会网络特别不好,nodejs npm 仓库 ...

  7. Web Fragment在项目中的使用

    Web Fragment 是什么 - 它是在 servlet 3.0开始支持的,可以把一个dy web项目拆分为多个项目,解耦合,使其在项目中开发效率提高,下面我演示简单的项目创建过程 用eclips ...

  8. (转)Java中使用正则表达式的一个简单例子及常用正则分享

    转自:http://www.jb51.net/article/67724.htm 这篇文章主要介绍了Java中使用正则表达式的一个简单例子及常用正则分享,本文用一个验证Email的例子讲解JAVA中如 ...

  9. dubbo 笔记-XML配置文件简介

    <dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心. eg.<dubbo:service r ...

  10. 【ASP.NET MVC 学习笔记】- 06 在MVC中使用Ninject

    本文参考:http://www.cnblogs.com/willick/p/3299077.html 1.在ASP.NET MVC中一个客户端请求是在特定的Controller的Action中处理的. ...