# 使用 Koa + MongoDB + Redis 搭建论坛系统
## 基础项目搭建
这一小节我们将使用一些 koa 的中间件开发一个简单的论坛系统。Nodeclub 是一个优秀的开源论坛系统,已在 Node.js 中文技术社区 CNode([http://cnodejs.org](http://cnodejs.org/)) 得到应用,我们仿照并借鉴 Nodeclub 从头搭建一个论坛系统。首先,构建基础项目结构如下:
![](https://www.writebug.com/myres/static/uploads/2021/11/24/8083d90538d46de5c6369ec7deba970b.writebug)
其中需要说明的有:
- bin/start:启动脚本
- config/:存放配置文件的目录,default.scheme.js 为 koa-scheme 所用
- lib/:存放一般代码文件的目录
- models/:存放模型文件的目录
- routes/:存放路由文件的目录
- theme/:存放主题模版文件的目录
- test/:存放测试文件的目录
修改 package.json,添加如下内容:
```
{
"name": "N-club",
"version": "0.0.1",
"description": "N-club for koa.",
"scripts": {
"start": "NODE_ENV=default DEBUG=* node --harmony app"
},
"dependencies": {
"co-cache": "2.3.0",
"co-ejs": "1.5.2",
"config-lite": "1.5.0",
"koa": "1.2.4",
"koa-bodyparser": "2.3.0",
"koa-errorhandler": "0.1.1",
"koa-flash": "1.0.0",
"koa-frouter": "0.5.0",
"koa-generic-session": "1.11.4",
"koa-generic-session-mongo": "0.3.1",
"koa-gzip": "0.1.0",
"koa-logger": "1.3.0",
"koa-router-cache": "2.0.0",
"koa-scheme": "2.2.1",
"koa-static-cache": "3.1.7",
"merge-descriptors": "1.0.1",
"mongoose": "4.2.9",
"validator": "6.2.0"
},
"engines": {
"node": ">=4"
}
}
```
保存并运行 `npm install`,其中:
- koa-bodyparser:请求体解析中间件,相当于 express 中的 body-parser
- koa-flash:相当于 connect-flash
- koa-generic-session:通用的 session 中间件,可结合 MongoDB、Redis 等使用
- koa-generic-session-mongo:结合 koa-generic-session,将 session 存储到 MongoDB 的中间件
- koa-static-cache:静态文件缓存中间件
- merge-descriptors:合并两个对象的工具模块
- mongoose:MongoDB 驱动模块
- validator:参数验证工具模块
修改 app.js,添加如下代码:
```
var app = require('koa')();
var logger = require('koa-logger');
var bodyparser = require('koa-bodyparser');
var staticCache = require('koa-static-cache');
var errorhandler = require('koa-errorhandler');
var session = require('koa-generic-session');
var MongoStore = require('koa-generic-session-mongo');
var flash = require('koa-flash');
var gzip = require('koa-gzip');
var scheme = require('koa-scheme');
var router = require('koa-frouter');
var routerCache = require('koa-router-cache');
var render = require('co-ejs');
var config = require('config-lite');
// 不放到 default.js 是为了避免循环依赖
var merge = require('merge-descriptors');
var core = require('./lib/core');
var renderConf = require(config.renderConf);
merge(renderConf.locals || {}, core, false);
app.keys = [renderConf.locals.$app.name];
app.use(errorhandler());
app.use(bodyparser());
app.use(staticCache(config.staticCacheConf));
app.use(logger());
app.use(session({
store: new MongoStore(config.mongodb)
}));
app.use(flash());
app.use(scheme(config.schemeConf));
app.use(routerCache(app, config.routerCacheConf));
app.use(gzip());
app.use(render(app, renderConf));
app.use(router(app, config.routerConf));
app.listen(config.port, function () {
console.log('Server listening on: ', config.port);
});
```
中间件的加载顺序十分重要,如上面的 errorhandler 中间件需要放到最上面,这样才能捕获下游抛出的错误。flash 中间件需要放到 session 中间件之后,因为 flash 功能是基于 session 实现的。routerCache 需要放到 router 前面,而 scheme 需要放到 routerCache 前面。 gzip 压缩中间件需要放到 routerCache 之后,这样 routerCache 缓存的就是 gzip 压缩后的内容了,大大减少了内存消耗量。
修改 default.js ,添加如下代码:
```
var path = require('path');
var cache = require('koa-router-cache');
var MemoryCache = cache.MemoryCache;
module.exports = {
port: process.env.PORT || 3000,
mongodb: {
url: 'mongodb://127.0.0.1:27017/club'
},
schemeConf: path.join(__dirname, './default.scheme'),
staticCacheConf: path.join(__dirname, '../theme/publices'),
renderConf: path.join(__dirname, '../theme/config'),
routerConf: 'routes',
routerCacheConf: {
'GET /': {
key: 'cache:index',
expire: 10 * 1000,
get: MemoryCache.get,
set: MemoryCache.set,
destroy: MemoryCache.destroy,
passthrough: function* passthrough(_cache) {
// 游客
if (!this.session || !this.session.user) {
if (_cache == null) {
return {
shouldCache: true,
shouldPass: true
};
}
this.type = 'text/html; charset=utf-8';
this.set('content-encoding', 'gzip');
this.body = _cache;
return {
shouldCache: true,
shouldPass: false
};
}
// 已登录用户
return {
shouldCache: false,
shouldPass: true
};
}
}
}
};
```
我们尽量把 app.js 中使用的配置信息放到了配置文件里,其中 ./lib/core.js 是暴漏出来的核心文件,将它与模版中自定义的 locals 合并作为 co-ejs 渲染时的本地变量,模板中还自定义了一个 $app 变量,保存了模版的主题信息。我们规定模板目录下的 publices 目录用来存放静态文件,config.js 保存了 co-ejs 的配置。我们还针对未登录的用户对主页进行了缓存,并设置 10 秒生存期。当命中缓存的时候,直接将缓存中的数据赋值到 this.body 返回,并设置正确的 header。shouldCache 控制是否缓存该路由,游客为 true,已登录用户则为 false;shouldPass 控制是否允许通过并执行后面的路由,如果缓存为空则通过,否则不通过。注意 shouldCache 和 shouldPass 是有语义和功能上的区别的。
## 路由和功能设计
本小节只是以开发一个简单的论坛原型为例学习 koa 的使用,所以只需要有基本的注册、登录、登出、发帖、评论、主页、用户页、话题页,有简单的版块和分页功能即可。
设计路由如下:
```
GET /signup //注册页
POST /signup //注册
GET /signin //登录页
POST /signin //登录
GET /logout //登出
GET /create //发帖页
POST /create //发帖
GET / //主页
GET /user/:name //用户页
GET /topic/:id //话题页
POST /topic/:id //评论
```
对应构建 routes 目录结构如下:
![](https://www.writebug.com/myres/static/uploads/2021/11/24/a98a54bbf0552fc18cadf00553334c64.writebug)
## 自定义模型
因为我们的论坛很简单,所以设计 users、topics 和 comments 三个集合即可满足需求,其中 users 集合用来存储用户信息,topics 集合用来存储话题信息,comments 集合用来存储话题的评论。构建 models 目录结构如下:
![](https://www.writebug.com/myres/static/uploads/2021/11/24/0a37e6c025b9fd98e47e1b802398a7ce.writebug)
我们使用 mongoose 的 Schema 来定义我们的数据模型,对应文件修改如下:
**user.js**
```
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true},
password: { type: String, required: true },
gender: { type: String, required: true },
signature: { type: String },
created_at: { type: Date, default: Date.now },
updated_at: { type: Date, default: Date.now }
});
UserSchema.index({name: 1});
module.exports = mongoose.model('User', UserSchema);
```
**topic.js**
```
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TopicSchema = new Schema({
user: {
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
100012617-使用 Koa + MongoDB + Redis 搭建论坛系统.zip (48个子文件)
kmrblog
lib
comment.js 289B
user.js 341B
topic.js 1KB
core.js 246B
app.js 1KB
LICENSE 1KB
package.json 961B
bin
start 95B
routes
create.js 354B
user
_name.js 197B
logout.js 79B
signin.js 569B
index.js 234B
topic
_id.js 525B
signup.js 524B
theme
partials
list.ejs 818B
linkCard.ejs 352B
noReplyCard.ejs 427B
createCard.ejs 168B
userCard.ejs 924B
tab.ejs 349B
pagination.ejs 935B
topic.ejs 923B
signup.ejs 2KB
publices
js
jquery-1.11.2.min.js 94KB
css
style.css 709B
images
cnode.png 8KB
index.ejs 632B
helpers
locals.js 91B
filters.js 429B
package.json 285B
comment.ejs 1KB
header.ejs 1KB
config.js 199B
footer.ejs 17B
user.ejs 506B
signin.ejs 591B
create.ejs 2KB
test
signup.js 1KB
models
comment.js 540B
user.js 486B
topic.js 662B
index.js 349B
.gitignore 167B
README.md 45KB
config
production.js 0B
default.scheme.js 3KB
default.js 1KB
共 48 条
- 1
资源评论
- m0_571529542023-06-19这个资源对我启发很大,受益匪浅,学到了很多,谢谢分享~
神仙别闹
- 粉丝: 2687
- 资源: 7649
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功