前言
这一章写的很没有底气,因为我完全不懂一个正经的后台应用是怎么结构分层的,
所有只能按照我自己的理解去写,即使这样也仅仅只分离出了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
}
}))
具体如图:
然后运行项目,看是否在数据库中自动创建了一个 _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()
})
}
})
})
}
utils
中index.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