包含功能
登录注册(不开放注册只是用固定的账号信息)
查看列表
查看详情
发布信息
编辑信息
删除信息
项目接口
npm init -y
npm install koa --save
npm istall koa-router --save (旧版本) 或者 npm install @koa/router --save (新版本)
npm install bluebird --save
npm install koa-ejs --save
npm install koa-bodyparser --save
执行完毕之后 ,使用vscode 打开项目文件夹,继续往里面添加对应的文件目录和文件
authenticate.js
//认证中间件
module.exports = async function (ctx,next) {
const logined = ctx.cookies.get('logined',{signed: true});
ctx.state.logined = !!logined;
await next();
}
路由开发
routes/post.js
const Router = require('koa-router');
const postService = require('../services/post');
const router = new Router();
//发布表单页面
router.get('/publish', async (ctx) => {
await ctx.render('publish');
});
//发布处理
router.post('/publish', async (ctx) => {
const data = ctx.body;
if (!data.title || !data.content) {
ctx.throw(500, '缺失必填参数');
}
const item = postService.publish(data.title, data.content);
ctx.redirect(`/post/${item.id}`);
});
//详情页面
router.get('/post/:postId', async (ctx) => {
const post = postService.show(ctx.params.postId);
if (!post) {
ctx.throw(404, '消息记录不存在');
}
await ctx.render('post', { post: post });
});
//编辑表单页面
router.get('/update/:postId',async (ctx)=>{
const post = postService.show(ctx.params.postId);
if (!post) {
ctx.throw(404, '消息记录不存在');
}
await ctx.render('post', { post: post });
});
//编辑处理
router.post('/update/:postId',async (ctx)=>{
const data = ctx.body;
if (!data.title || !data.content) {
ctx.throw(500, '缺失必填参数');
}
const postId = ctx.params.postId;
postService.update(postId,data.title,data.content);
ctx.redirect(`/post/${postId}`);
});
//删除
router.get('delete/:postId',async (ctx)=>{
postService.delete(ctx.params.postId);
ctx.redirect('/');
});
module.exports = router;
routes/site.js
const Router = require('koa-router');
const postService = require('../services/post');
const router = new Router();
//网站首页
router.get('/', async (ctx)={
const list = postService.list();
await ctx.render('index',{
list : list
});
});
module.exports = router;
routes/user.js
const Router = require('koa-router');
const userService = require('../services/user');
const router = new Router();
//登陆页面
router.get('/login', async(ctx) = {
await ctx.render('login');
});
//登录处理
router.post('/login', async(ctx) = {
const data = ctx.request.body;
if(!data.userName || !data.password){
ctx.throw(500, '用户名或密码缺失必填参数');
}
const logined = userService.login(data.userName, data.password);
if (!logined) {
ctx.throw(500, '用户名或密码错误');
}
ctx.cookies.set('logined', 1, {
signed: true,
httpOnly: true
});
ctx.router('/', '登陆成功');
});
//退出登录
router.get('/logout', (ctx) => {
ctx.cookies.set('logined', 0, {
signed: true,
maxAge: -1
});
ctx.router('/', '退出登陆成功');
});
```
**服务层开发
services/post.js**
```
const fs = require('fs');
const bluebird = require('bluebird');
//Promise 化 fs 的api
bluebird.promisifyAll(fs);
//文章数据
const posts = [];
//文章ID
let postId = 1;
//发表文章
exports.publish = function(title,content){
const item = {
id: postId++,
title: title,
content: content,
time: (new Date()).toLocaleDateString()
};
posts.push(item);
return item;
}
//查看文章
exports.show = function(id){
id = Number(id);
for(const post of posts){
if(post.id === id){
return post;
}
}
return null;
}
//编辑文章
exports.update =function(id,title,content){
id = Number(id);
posts.forEach((post)=>{
if(post.id === id){
post.title = title;
post.content = content;
}
});
}
//删除文章
exports.delete = function (id){
id = Number(id);
let index = -1;
posts.forEach((post)=>{
if(post.id === id){
index = id;
}
});
if(index > -1){
posts.slice(index,1)
}
}
exports.list = function(){
return posts.map(item => item);
}
```
**serivce/user.js**
```
const user = {
liuyifei: 'password'
};
//登录
exports.login = function(userName,password){
if(user[userName] === undefined){
return false;
}
return user[userName] === password;
};
```
=======================================================
**前端模板:**
**index.ejs**
```
<h1>文章显示列表</h1>
<% if(list.length === 0){ %>
<p>文章显示列表</p>
<% }else{ %>
<table>
<tr>
<th>id</th>
<th>标题</th>
<th>发布时间</th>
<% if(logined){ %>
<th>操作</th>
<% } %>
</tr>
<% list.forEach(post => { %>
<td><%= post.id %></td>
<td><a href="/post/<%= post.id %>"><%= post.title %></a></td>
<td><%= post.time %></td>
<% if(logined){ %>
<th><a href="/update/<%= post.id %>">编辑</a></th>
<th><a href="/delete/<%= post.id %>" onclick="return confirm('确认删除?')">删除</a></th>
<% } %>
<% }) %>
</table>
<% } %>
```
**login.ejs**
```
<form action="/login" method="post" enctype="application/x-www-form-urlencoded">
<fieldset>
<legend>登录</legend>
<div>
<label for="userName">账号</label>
<input type="text" name="userName" id="userName" required />
</div>
<div>
<label for="userName">密码</label>
<input type="password" name="password" id="password" required />
</div>
<div>
<button type="submit">登录</button>
</div>
</fieldset>
</form>
```
**main.ejs**
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>首页</title>
</head>
<body>
<% if(logined) { %>
<a href="/">首页</a>
<a href="/publish">发表文章</a>
<a href="/logout">退出登录</a>
<% }else{%>
<a href="/login">退出登录</a>
<% } %>
<%- body %>
</body>
</html>
```
**post.ejs**
```
<div>
<h1><%= post.title %></h1>
<time>发布时间:<%= post.time %></time>
<hr>
<div>
<%= post.content %>
</div>
</div>
```
**publish.ejs**
```
<form action="/publish" method="post" enctype="application/x-www-form-urlencoded">
<fieldset>
<legend>发表文章</legend>
<div>
<label for="title">标题</label>
<input type="text" name="title" id="title" required>
</div>
<div>
<label for="content">内容</label>
<textarea name="content" id="content" required></textarea>
</div>
<div>
<button type="submit">发布</button>
<button type="reset">重置</button>
</div>
</fieldset>
</form>
```
****update.ejs****
```
<form action="/update/<%=post.id %>" method="post" enctype="application/x-www-form-urlencoded">
<fieldset>
<legend>编辑文章</legend>
<div>
<label for="title">标题</label>
<input type="text" name="title" id="title" value="<%= post.title %>" required>
</div>
<div>
<label for="content">内容</label>
<textarea name="content" id="content" required >
<%= post.content %>
</textarea>
</div>
<div>
<button type="submit">发布</button>
<button type="reset">重置</button>
</div>
</fieldset>
</fieldset>
</form>
```
**index.js : 项目的入口文件,负责挂载中间件,路由,应用配置以及启动服务器**
```
const Koa = require('koa');
const render = reuire('koa-ejs');
const bodyParser = require('koa-bodyParser');
//认证组件
const authenticate = require('./middlewares/authenticate');
//路由
const siteRoute = require('./routes/site');
const userRoute = require('./routes/user');
const postRoute = require('./routes/post');
const app = new Koa(); //定义服务
app.keys = ['wusoddn09Wa']; //定义认证使用的key
//挂载中间件
app.use(bodyParser());
//关联使用模版
render(
app,{
root: './templates',
layout: 'main',
viewExt: 'ejs'
}
);
//挂载路由
app.use(siteRoute.routes()).use(siteRoute.allowedMethods());
app.use(userRoute.routes()).use(userRoute.allowedMethods());
app.use(postRoute.routes()).use(postRoute.allowedMethods());
app.listen(8080,()=>{
console.log(server start up on port: 8080);
});
```