koa2学习笔记03 - 给koa2配置session ——koa2结构分层、配置数据库、接口

前言

这一章写的很没有底气,因为我完全不懂一个正经的后台应用是怎么结构分层的,
所有只能按照我自己的理解去写,即使这样也仅仅只分离出了controller层,
至于所谓的service层,dao层,完全不懂该怎么分离出来。
所以这一章仅供参考。如果有人能指点一下,不胜感激。

正文

数据库是采用的mysql,所以需要在本机安装一个mysql。
具体安装这里不多说了,请移步 菜鸟教程
置于MySQL图形化管理工具推荐使用 navicat 或者 heidisql

1 安装依赖

npm install koa-session-minimal koa-mysql-session mysql --save

2 配置数据库和session

config 目录下新建 config.js 放置配置文件。

const database = {
    host: '127.0.0.1',			// 数据库地址,本机默认127.0.0.1
    port: 3306,					// 数据库默认端口
    database: 'koa2db',			// 数据库名字
    user: 'root',				// 数据库默认用户名
    password: 'XXXX'			// 你设置的数据库密码
}

module.exports = {
    database: database
}

改造根目录下的 app.js

//  配置session
app.use(session({
    key: 'USER_SID',
    store: new MysqlStore(mysqlConfig),
    cookie: {
        maxAge: 1000 * 60 * 60 * 24, // cookie有效时长
        overwrite: false
    }
}))

具体如图:
配置session
然后运行项目,看是否在数据库中自动创建了一个 _mysql_session_store 的表。 如果成功说明配置成功。
在这里插入图片描述

3 配置接口,分离controller

在目录 router 中新建 api 目录,放置各模块接口。再新建api.js作为 api的入口文件。
我们可以在里面加入一些测试接口,捕获不存在的接口、输出不存在的错误接口方便排查。

api.js

const router = require('koa-router')();
const user = require('./api/user.js');

router.prefix('/api');   // 统一定义接口前缀都为api, 之后写的所有接口都在api下。

user(router);

/* 测试接口 */
router.get('/', function (ctx, next) {
    ctx.body = {
        code: 0,
        data: null,
        msg: "接口请求成功",
        request: ctx.originalUrl
    }
})

/* 404 */
router.all('/*', function (ctx, next) {
    ctx.body = {
        code: 1001,
        ctx: ctx,
        data: null,
        msg: "接口不存在",
        request: ctx.originalUrl
    }
})
module.exports = router

// router.get()  ==>  仅仅get请求可以访问到接口
// router.post() ==>  仅仅post请求可以访问到接口
// router.all()  ==>  所有请求都可以访问到接口

定义好了接口的入口文件,我们先在 app.js 引入

在这里插入图片描述

引入之后接下来配置接口的详细信息,在routers 中 新建api目录, 并在其中新建 user.js

/**
 * 用户相关接口
 */
const user = require("../../controller/user.js")

module.exports = function(router) {
	router.all('/user/login', user.userLogin)
	router.all('/user/isLogin', user.isLogin)
}

根目录下新建目录 controller controller 下新建 user.js, 此处暂不考虑密码明文传输安全性问题。

const { responseFormatter, getParams } = require("../utils/index.js") //	格式化输出方法、获取参数方法
const { logHandle } = require("../utils/logs.js") //  上一章记录操作日志的方法
const handleDB = require("../utils/handleDb.js") //  操作数据库方法

// 用户登录接口
async function userLogin(ctx, next) {
    var params = getParams(ctx.request)
    try {
        let sql = "select * from user where username=? and password=?"
        let data = await handleDB(sql, [params.username, params.password]);
        // 记录登录日志
        logHandle({
            title: '用户登录',
            sql,
            params,
            data
        });
        if (data.length) {
            // 存入session信息(最终会存在数据库中)
            ctx.session = {
                isLogin: true,
                userId: data[0].userId,
                userName: data[0].username,
                nickName: data[0].nickname
            }
            ctx.body = responseFormatter(0, '登录成功!');
        } else {
            ctx.body = responseFormatter(201);
        }
    } catch (err) {
        ctx.body = responseFormatter(103, err);
    }
}

// 检测用户是否登录接口
async function isLogin(ctx, next) {
    if (ctx.session && ctx.session.isLogin) {
        ctx.body = responseFormatter(0, {
            nickName: ctx.session.nickName
        });
    } else {
        ctx.body = responseFormatter(202);
    }
}

module.exports = {
    isLogin,
    userLogin
}

utils 目录下的 index.js

/**
 * @name responseFormatter   格式化输出响应结果
 * @params { @Number 状态码, @Object 返回数据}
 * @return { @Object }
 * @author HoChine.
 */

const errorCode = require("../config/errorCode.js")
exports.responseFormatter = function (code, data) {
    return {
        code: code,
        msg: errorCode[code],
        data: data || null
    }
}

/**
 * @name getParams 获取url参数
 * @params { @String url}
 * @return { @Object }
 * @author HoChine.
 */

let getUrlParams = function (url) {
    let paramsList = {};
    if (!url) {
        console.log("url 为必填项");
        return paramsList;
    }
    let paramsStr = url.split("?")[1];
    let params = paramsStr ? paramsStr.split("&") : [];
    params.forEach(function (item) {
        let temp = item.split("=");
        temp[0] ? paramsList[temp[0]] = temp[1] : '';
    })
    
    return paramsList;
}
exports.getUrlParams = getUrlParams

/**
 * @name getParams 根据请求方式不同获取参数
 * @params { @Object ctx.request}
 * @return { @Object }
 * @author HoChine.
 */
exports.getParams = function (request) {
    if (request.method === "GET") {
        return getUrlParams(request.url)
    }else{
        return request.body
    }
}

utils 目录下的 handleDb.js 。 database为上面的数据库配置文件

onst mysql = require('mysql')
const { database } = require('../config/config');
const pool = mysql.createPool(database);

module.exports = function(sql, values) {
    return new Promise((resolve, reject) => {
        pool.getConnection(function(err, connection) {
            if (err) {
                reject(err)
            } else {
                connection.query(sql, values, (err, rows) => {
                    if (err) {
                        reject(err)
                    } else {
                        resolve(rows)
                    }
                    connection.release()
                })
            }
        })
    })
}

utilsindex.js 所引入的 errorCode.js

/*  错误码1-2位按服务端业务模块区分
 *  01. 接口相关 (参数不全等,参数有误)
 *  02. user相关
 *  03. blog相关
*/

/*  错误码3-4位按具体错误情况排列
 *  01.
 *  02.
*/

module.exports = {
    0: 'success',
    101: '缺少必须参数!',
    102: '参数有误!',
    103: '接口异常',
    201: '用户不存在!',
    202: '用户未登录或已过期!',
    203: '用户名或密码错误,请重试!',
    220: '抱歉,您没有权限!',
    9999: '未知错误!'
};

最后配置一下数据库 随意新增一条数据。
在这里插入图片描述

在这里插入图片描述
至此,接口、session、数据库配置基本上配置好了。

4 前台页面验证

view 目录下的 index.html (是我不知道在哪抄来的一个登录模块样式)

<!DOCTYPE HTML>
<html>

<head>
    <title>Home</title>
    <link href="/stylesheets/style.css" rel="stylesheet" />
</head>

<body>
    <div class="login" style="display:none">
        <h2>商家登录 </h2>
        <div class="login-top">
            <h1>登录</h1>
            <form>
                <input type="text" id="username" placeholder="用户名" value="admin">
                <input type="password" id="password" placeholder="******" value="admin">
            </form>
            <div class="forgot">
                <a href="#">忘记密码?</a>
                <input type="button" id="login" value="登录">
            </div>
        </div>
        <div class="login-bottom">
            <h3>400-000-0000</h3>
        </div>
    </div>
    <div class="logined" style="display:none"></div>
</body>
<script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script>
<script src="/javascripts/index.js"></script>

</html>

public 中的 stylesheets 样式文件,具体可以github上复制,放这里太占篇幅 。 style.css点这里
public 中的 javascripts 登录逻辑随便写写,不要深究写的SB不SB,只是测试接口用。

$(function() {

	isLogin()
	
	function isLogin() {
		$.get("http://localhost:3000/api/user/isLogin", function(res) {
			console.log(res);
			if (res.code) {
				$(".login").show();
				login()
			} else {
				$(".logined").show().text("hello, " + res.data.nickName)
			}
		})
	}

	function login() {
		$("#login").on("click", function() {
			var username = $("#username").val();
			var password = $("#password").val();
			if (username && password) {
				$.post("http://localhost:3000/api/user/login", {
					username: username,
					password: password
				}, function(res) {
					console.log(res);
					if(!res.code){
						alert(res.data);
						location.reload();
					}
				})
			} else {
				alert("用户名或密码为空")
			}

		})
	}
})

作者 HoChine
2019 年 04月 16日
GitHub地址:https://github.com/HoChine/Koa2-demo/tree/03

posted @ 2019-04-16 16:07  HoChine  阅读(689)  评论(0编辑  收藏  举报