1.需求分析
# 需求很重要
-需求:描述项目最终效果的文字和图
-产品经理写需求,然后要经过各个项目角色的评审通过
-需求一般包括:原型图,功能描述
# 原型图
-注册页
-登录页
-主页
# 功能描述
-用户名唯一,不能重复注册
-用户名和密码匹配,即可登录
-登录成功后,跳转到首页
-非登录用户不能进入首页,登录用户可发布留言
-可产看全部留言,或查看自己的留言
-只能编辑和删除自己的留言,无权操作他人留言
2.数据库设计
# mongodb创建数据库
-创建数据库comment
-创建comments,存储留言数据
-创建users,存储用户
# mongoose定义Schema和Model
-回顾mongoose
-定义Schema
-定义Model
3.接口(路由)设计
# 需要哪些接口?
-注册
-登录
-获取留言
-创建留言
-更新
-删除
# 哪些接口需要登录验证?
-登录不需要
-注册不需要
-其他都需要
# 登录如何实现(跨域传递cookie)
4.初始化开发环境
# 初始化koa2环境
-安装脚手架: npm install -g koa-generator
-项目命名并生成环境: koa2 messageitem
-进入项目: cd Item
-安装所有依赖文件: npm install
-在根目录新建src文件,把public、routers、views、app.js移入src中
# 规范目录和层级
-路由-->controller-->db-->数据库
| |
中间件 Model
# 连接数据库
-安装mongoose npm install mongoose --save
-连接mongodb
-Schema和Model
5.项目开发
# 前端代码
# 跨域&跨域传递cookie
-需要插件: npm i koa2-cors --save
-登录需要设置session:需要插件:npm install koa-generic-session --save
# 接口开发&前后端联调
/**入口文件及配置 app.js*/
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const cors = require('koa2-cors')
const session = require('koa-generic-session')
const index = require('./routes/index')
const users = require('./routes/users')
const comment = require('./routes/comment')
// error handler
onerror(app)
//允许服务端支持跨域
app.use(cors({
origin: 'http://localhost:8080', // 支持前端哪个域,可以跨域
credentials: true // 允许跨域的时候带着 cookie
}))
//配置 session
app.keys = ['yyhZDMY^1024'];//设置密钥,携带在cookie
app.use(session({
path:'/',
httpOnly: true,//只允许服务端来操作cookie
maxAge: 24 * 60 * 60 * 1000
}))
// middlewares
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'pug'
}))
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
// routes
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
app.use(comment.routes(), comment.allowedMethods())
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app
//db.js
//连接数据库的处理模块(Module)
const mongoose = require('mongoose');
const url = 'mongodb://localhost:27017';
const dbName = 'comment3';
//配置
// mongoose.set('useCreateIndex',true);
// mongoose.set('useFindAndModify',false);
//开始连接
mongoose.connect(`${url}/${dbName}`,{
useNewUrlParser: true,
useUnifiedTopology: true
});
//获取连接所需要的信息提示connection对象
const conn = mongoose.connection;
//连接错误处理
conn.on('error',err =>{
console.log('mongodb 连接失败',err);
})
//把连接数据的一些处理module导出去
module.exports = mongoose;
/*model-Schema*/
//Comment.js
//留言的数据库模型
const mongoose = require('../db/db');
const CommentSchema = mongoose.Schema({
content: {
type: String,
required: true
},
username: String,
}, { timestamps:true })
//mongoose会自动把comment collection创建出来
const Comment = mongoose.model('comment',CommentSchema);
module.exports = Comment;
/**User.js**/
//用户的数据库模型(module)
const mongoose = require('../db/db');
const UserSchema = mongoose.Schema({
username: {
type: String,
required: true,
unique: true //唯一
},
password: String,
age: Number,
city: String,
gender: {
type: Number,
default: 0 //0-保密,1-男,2-女
}
}, { timestamps: true });
//通过mongoose.mode把上面的处理定义成模型
const User = mongoose.model('user',UserSchema);
module.exports = User;
/**router路由代码*/
/*comment.js*/
//留言功能的路由
const router = require('koa-router')();
const loginCheck = require('../middleware/loginCheck');
const { create, getList, del, update } = require('../controller/comment');
router.prefix('/comment');
//更新留言
router.post('/update',loginCheck,async(ctx, next)=>{
//获取id , content
const{ _id, content } = ctx.request.body;
//获取用户名
const { username } = ctx.session.userInfo;
//执行更新
try{
const newData = await update(_id, username, content);
ctx.body = {
errno: 0,
data: newData
}
}catch(ex){
console.error('更新失败',ex);
ctx.body = {
errno: -1,
message: '更新失败'
}
}
})
//删除留言
router.post('/del',loginCheck,async(ctx,next)=>{
//获取id
const { _id } = ctx.request.body;
//获取用户名
const { username } = ctx.session.userInfo;
//执行删除(交给controller处理)
try{
await del(_id, username);
ctx.body = {
errno: 0,
}
}catch(ex){
//失败
console.error('删除失败',ex);
ctx.body = {
errno: -1,
message: '删除失败'
}
}
})
//获取留言列表
router.get('/list',loginCheck,async(ctx,next)=>{
//获取filterType = 1查看全部,2查看自己
let { filterType } = ctx.query;
filterType = parseInt(filterType) || 1;
//获取当前用户名
let username = '';
if(filterType == 2) {
username = ctx.session.userInfo.username;
}
//获取留言列表
const list = await getList(username);
ctx.body = {
errno: 0,
data: list
}
})
//插入新留言
router.post('/create',loginCheck,async(ctx,next)=>{
//获取留言内容
const { content } = ctx.request.body;
//从session中获取用户
const { username } = ctx.session.userInfo;
//提交留言,其功能交给controller处理
const newComment = await create(content, username);
//返回
ctx.body = {
errno: 0,
data: newComment
}
})
module.exports = router;
/**index.js*/
const router = require('koa-router')()
router.get('/', async (ctx, next) => {
await ctx.render('index', {
title: 'Hello Koa 2!'
})
})
router.get('/string', async (ctx, next) => {
ctx.body = 'koa2 string'
})
router.get('/json', async (ctx, next) => {
ctx.body = {
title: 'koa2 json'
}
})
module.exports = router
/*users.js*/
const router = require('koa-router')()
const { register,login } = require('../controller/user');
const loginCheck = require('../middleware/loginCheck');
router.prefix('/users');//前缀
//获取用户信息之前先进行登录校验
router.get('/getUserInfo',loginCheck, async(ctx, next)=>{
ctx.body = {
errno: 0,
data: ctx.session.userInfo
}
})
//登录路由
router.post('/login',async(ctx,next)=>{
//获取登录信息
const { username, password } = ctx.request.body;
//验证登录(让controller处理)
const res = await login(username, password); //调用controllor
if(res){
//登录成功需要设置session(即在session存什么)
ctx.session.userInfo = {
username
}
ctx.body = {
errno: 0
}
}else{
ctx.body = {
errno: -1,
message: '登录失败'
}
}
})
//注册路由
router.post('/register',async(ctx, next)=>{
//获取注册信息(前端传过来的)
const userInfo = ctx.request.body;
/*提交注册(即把获取的注册信息放到数据库里),把注册功能交给controller(多一层结构更清晰),里定义一个注册功能,
然后引入这个功能(是一个函数)*/
try{
const newUser = await register(userInfo);//调用controller
ctx.body = {
errno: 0,
data: newUser
}
} catch(ex){
console.error('注册失败',ex);
ctx.box = {
errno: -1,
message: '注册失败'
}
}
})
module.exports = router
/**middleware中间件*/
/*loginCheck.js*/
//登录验证的中间件
async function loginCheck(ctx, next){
const session = ctx.session || {}
const userInfo = session.userInfo
if(userInfo && userInfo.username){
//登录验证成功
await next();
return;
}else{
//登录验证失败
ctx.body = {
errno: -1,
message: '用户尚未登录'
}
}
}
module.exports = loginCheck;
/*Controller控制器*/
/**user.js*/
//user controller
const User = require('../model/User');
//登录功能
async function login(username, password){
//从数据查找是否存在
const user = await User.findOne({username,password});
if(user !== null){
//说明在数据库找到了
//登录成功
return true;//返回给routes/users.js
}else{
//登录失败
return false;
}
}
//注册的功能
async function register(userInfo = {}){
//userInfo存储了注册信息
//把userInfo存入数据库
const newUser = await User.create(userInfo);
//返回注册的用户信息
return newUser;
}
module.exports = {
register,
login
}
/*comment.js*/
const Comment = require('../model/Comment')
//更新留言
async function update(_id, username, content){
const newData = await Comment.findOneAndUpdate(
{ _id, username }, //更条件
{ content }, //更新内容
{ new: true } //返回更新后的留言
)
return newData;
}
//删除留言
async function del(_id, username){
await Comment.remove({
_id,
username //只能删除自己的留言
})
}
//获取留言列表
async function getList(username = ''){
const whereOpt = {}
if(username){
whereOpt.username = username;
}
const list = await Comment.find(whereOpt).sort({_id: -1});
return list;
}
//创建留言的数据库
async function create(content, username){
//创建数据库后并保存到数据库
const newComment = await Comment.create({
content,
username
})
return newComment
}
module.exports = {
create,
getList,
del,
update
}