Table of Contents generated with DocToc
自己身为以前端开发为主的工程师,虽然也使用过PostgreSQL,SQLite,MySql这些数据库,但还是更偏向于MongoDB,因为觉得它对于前端更友好(JSON数据格式的储存),学习成本很低,和Node搭配的也不错。因此,接下来会使用mongodb
作为和Koa2配合的数据库。
接下来,会通过mongodb创建一个ToDo-APP
如果对mongodb不熟悉,我墙裂推荐看MongoDB 极简实践入门入门
先在本地安装并配置MongoDB
$ npm install --save mongoose
在项目内建立model
// app/models/todo.js
// 定义数据结构
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
// 定义TodoSchema数据表和数据结构
const TodoSchema = new Schema({
content: { type: String, required: true },
complete: { type: Boolean, required: true, default: false },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now },
user: { type: String, required: true }
});
// 使用content字段作为索引
TodoSchema.index({content: 1});
// 使用Todo名称来调用表
export default mongoose.model('Todo', TodoSchema);
然后在models/index.js
中启动数据库:
// app/models/index.js
import mongoose from 'mongoose';
// 事先创建了名为koa2-todo的数据库
mongoose.connect('mongodb://127.0.0.1:27017/koa2-todo', function (err) {
if (err) {
console.error('connect to %s error: ', 'koa2-todo', err.message);
process.exit(1);
}
});
import Todo from './todo';
export default {Todo};
这样,在调用models/index.js
的时候,会连接koa2-todo
数据库,并且会在没有TodoSchema
数据表的时候新建数据表
虽然model
好了,但我们在使用的时候不会直接调用Todo
数据表来操作,而是再做一层封装,把数据的各个操作借口封装到我们需要的函数里,然后再暴露出去。
数据库的操作是异步的,不过好在mongoose
已经为我们封装成了Promise
。
// app/services/todo.js
import Model from '../models/index';
const getTodos = () => {
return new Promise((resolve, reject) => {
Model.Todo.find().exec().then((result) => {
resolve(result);
});
});
};
const addTodo = (options) => {
return new Promise((resolve, reject) => {
Model.Todo.create(options).then((result) => {
resolve(result);
});
});
};
export default {
getTodos,
addTodo
}
之后需要新建controller
,来进行操作的调用:
// app/controllers/todo.js
import Todo from '../services/todo';
// todo-app首页,渲染所有ToDo,并可以新建ToDo
const todoIndex = async (ctx, next) => {
const todos = await Todo.getTodos(user.name);
await ctx.render('todo/index', {
todos: todos,
csrf: ctx.csrf,
title: 'todos index'
});
};
// 通过表单的post新建一个ToDo,并返回列表页
const addTodo = async (ctx, next) => {
const requestData = ctx.request.body;
const todo = {
content: requestData.content
}
await Todo.addTodo(todo);
ctx.redirect('/todo');
};
export default {
addTodo,
todoIndex
}
最后就是router
和view
层:
// app/routes/todo.js
import koaRouter from 'koa-router';
import todo from '../controllers/todo';
const router = koaRouter({
prefix: '/todo'
});
router.post('/new', todo.addNew);
router.get('/', todo.todoIndex);
module.exports = router;
<!-- app/templates/todo/index.html -->
{% extends "layouts/base.html" %}
{% block body %}
<!-- 用来新建ToDo的表单,使用POST方法,并且要传入csrf -->
<form action="/todo/new" method="post">
<input type="hidden" name="_csrf" value="{{ csrf }}" />
<input type="hidden" name="utf8" value="✓" />
<input type="text" name="content"/>
<input type="submit" value="submit"/>
</form>
<ul>
{% for todo in todos %}
<li data-id="{{ todo._id }}">
<span class="todo_content">
{{ todo.content }}
</span>
</li>
{% endfor %}
</ul>
{% endblock %}