其实复习一次的作用真实太大了,真的,自从上次ajax开始其实就开始i有点懵懵懂懂的感觉,一直拖想到了node在去回顾一遍,这一次回去复习,ajax已经很熟练了,node之前搞不懂那些原理也顺清楚了好多,其实这次复习没有什么需要说的知识点,因为要说的前面都说过了,我来说一下这个做的一个大项目吧,这个项目真的,应该是我不熟练的愿意那边,就是用express写接口,用postman来测试,三个模块,三个数据库,基本上都在我的代码里面了,写的很详细步骤,用到的技术,基本上是用node的express模块,去写接口,然后中途中到了一些中间件,比如规定语义规则的joi,比如给密码解码加密的bcryptjs,我做了一天才做下来这一个案例

一个项目初试化,首先要创立一个单独的项目文件夹,然后终端npm init直接安装package.json,api.js接口文件,路由模块创立一个文件夹夹,路由函数又要分为一个模块,再把数据库创立好,基本就可以开始完成功能需求了,用后端node完成增删改查

项目文件分类:

1

接口文件

// 1.初始化
// 1.1创建项目
const express = require('express')
const app = express()
// 1.2配置跨域
const cors = require('cors')
app.use(cors())
// 1.3配置解析表单中间件
// 错误点:记住要有参数
app.use(express.urlencoded({extended : false})) // 2.3因为后面处理函数用到了很多res.send所以封装为一个全局中间件,给res绑定一个函数,那后面的中间件路由都可以用到这个函数了
app.use((req, res, next) => {
res.cc = function(err, status = 1) {
res.send({
status,
msg : err instanceof Error ? err.message : err
})
}
next()
}) // 2.4.6配置解析token的中间件
const expressJWT = require('express-jwt')
const secretKey = require('./secretKey')
app.use(expressJWT({secret : secretKey.secretKey, algorithms : ['HS256']}).unless({path : [/^\/api\//]})) // 1.4.4导入路由模块
const routerUser = require('./router/user')
const Joi = require('joi')
const { expressjwt } = require('express-jwt')
const { path } = require('express/lib/application')
app.use('/api', routerUser)
// 3.1.1个人中心路由导入
const infoRouter = require('./router/userinfo')
app.use('/my', infoRouter) // 4.1.2文章管理导入
const article = require('./router/acticle')
app.use('/my/article', article) // 5.1.2发布文章路由导入
const cates = require('./router/cate')
app.use('/my/article', cates) // 2.2.3定义规则joi的错误级别中间件
app.use((err, req, res, next) => {
if (err instanceof Joi.ValidationError) return res.send(err.message)
// 2.4.7增加jwt错误中间件
if (err.name == 'UnauthorizedError') return res.cc('身份认证失败')
return res.send('其他错误')
}) app.listen(80, () => {
console.log('http://127.0.0.1');
})

2.

写好接口文件该去给路由创建模块

// 1.4初始化路由相关文件夹 不光要给路由分装一个模块 里面的处理函数也要有一个模块
const express = require('express')
const { append } = require('express/lib/response')
const router = express.Router()
// 1.4.2导入路由处理函数
const routerHandler = require('../router_handler/user') // 注册
// 2.2.2导入joi验证输入进来的是否合法
const expressJOI = require('@escook/express-joi')
const {schema_user_info} = require('../schema/user')
router.post('/reguser',expressJOI(schema_user_info), routerHandler.getReguser) // 2.4登录
// 2.4.1添加语法规则,可以直接用注册的
router.post('/login',expressJOI(schema_user_info), routerHandler.getLogin) module.exports = router

3.

处理函数模块

// 1.4.1初始化路由处理函数模块

//注册
const db = require('../mysql')
//导入密码加密解密包
const bcrypt = require('bcryptjs')
function getReguser(req, res) {
// res.send('这里是注册模块')
// 2.2.4检测用户名是否被占用 导入mysql
let selectUser = 'select * from users where username = ?'
db.query(selectUser, req.body.username, (err, results) => {
// 2.3.1用到我们前面定义的全局中间件优化res.send
if (err) return res.cc(err)
if (results.length == 1) return res.cc('用户名已被占用')
// 2.2.5如果过了前两关的验证 基本可以验证成功了 就先对密码进行加密处理安装bcryptjs
req.body.password = bcrypt.hashSync(req.body.password, 10)
// console.log(req.body.password);
// 2.2.6插入新用户
let insertUser = 'insert into users set ?'
// -------------注意一下这里插入数据库的参数怎么写的
db.query(insertUser, [{username : req.body.username, password : req.body.password}], (err, results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('注册失败')
res.cc('注册成功',0)
})
})
} //登录
// 2.4.4.1导入jwt
const jwt = require('jsonwebtoken')
const secretKey = require('../secretKey')
const { result } = require('@hapi/joi/lib/base')
function getLogin(req, res) {
// res.send('这里是登录模块')
// 2.4.2根据用户名查询用户的数据
let selectLoginuser = 'select * from users where username = ?'
db.query(selectLoginuser, req.body.username, (err, results) => {
if (err) res.cc(err)
if (results.length !== 1) res.cc('未找到该用户')
// 2.4.3有数据就去判断密码是否正确
// console.log(results);
if (!bcrypt.compareSync(req.body.password, results[0].password)) return res.cc('密码错误')
// 2.4.4用户名有,密码 也对上了说明登陆成功,开始jwt身份认证
// 先剔除密码和头像的值
let user = {...results[0], password : '', user_pic: '',algorithms : ['HS256']}
let userToken = jwt.sign(user, secretKey.secretKey, {expiresIn : '1h'})
// 2.4.5向客户端发送token
res.send({
status : 0,
msg : '登录成功',
token : 'Bearer ' + userToken
})
})
} // 获取用户基本信息
function getInfo(req,res) {
// res.send('个人中心')
// 3.1.2获取用户基本信息
let selectInfo = 'select id,username,nickname,email,user_pic from users where id = ?'
db.query(selectInfo, req.user.id, (err, results) => {
if (err) return res.cc(err)
if (results.length !== 1) return res.cc('获取信息失败')
res.send({
status : 0,
msg : '获取信息成功',
data : results[0]
})
})
} // 3.2更新用户信息
function updateInfo(req, res) {
// res.send('更新用户信息')
// 3.2.4更新用户功能
let updateInfo = 'update users set ? where id = ?'
db.query(updateInfo, [req.body, req.user.id], (err, results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('更新信息失败')
res.cc('更新信息成功', 0)
})
} // 3.3重置密码
function updatePwd(req, res) {
// res.send('重置密码')
// 3.3.2查询用户是否存在
let selectExist = 'select * from users where id = ?'
db.query(selectExist, req.user.id, (err, results) => {
if (err) return res.cc(err)
if (results.length !== 1) return res.cc('用户不存在')
// 3.3.3前面那一步虽然无所谓但这一步必须的 判断输入的旧密码是否正确
if(!bcrypt.compareSync(req.body.oldPwd, results[0].password)) return res.cc('输入密码错误')
// 3.3.4对新密码加密后更新到数据库
let password = bcrypt.hashSync(req.body.newPwd)
let updatePwd = 'update users set password =? where id =?'
db.query(updatePwd, [password,req.user.id], (err, results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('修改密码失败')
res.cc('更新密码成功', 0)
})
})
} // 3.4更换头像
function updateAvatar(req, res) {
// res.send('更换头像')
// 3.4.3
let updateAvatar = 'update users set user_pic = ? where id = ?'
db.query(updateAvatar, [req.body.avatar, req.user.id], (err, results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('更新头像失败')
res.cc('更新头像成功', 0)
})
}
module.exports = {
getLogin,
getReguser,
getInfo,
updateInfo,
updatePwd,
updateAvatar
}

4.

这个时候就可以去api入口文件测试一下了,然后在数据库写好我们的数据表,创立一个js文件链接数据库

// 2.登录注册
// 2.1建好数据库后配置数据库
const { result } = require('@hapi/joi/lib/base')
const mysql = require('mysql')
const db = mysql.createPool({
host : '127.0.0.1',
user : 'root',
password : 'admin123',
database : 'mydb'
}) // 测试
/* db.query('select 1' , (err, results) => {
if(err) return console.log(err.message);
return console.log(results);
}) */ module.exports = db

5.

没记错的话,在登录接口应该使用jwt认证机制生成token吧

const express = require('express')
const router = express.Router()
const routerHandler = require('../router_handler/user')
// 3.个人中心
// 3.1获取用户基本信息
router.get('/userinfo', routerHandler.getInfo) // 3.2.1更新用户信息
// 3.2.3添加验证规则
const expressJoi = require('@escook/express-joi')
const {schema_update_info, schema_update_avatar} = require('../schema/user')
router.post('/userinfo',expressJoi(schema_update_info),routerHandler.updateInfo) // 3.3.1重置密码
const {schema_update_pwd} = require('../schema/user')
router.post('/updatepwd',expressJoi(schema_update_pwd), routerHandler.updatePwd) // 3.4.1更换头像
const {schema_updatee_avatar} = require('../schema/user')
router.post('/update/avatar',expressJoi(schema_updatee_avatar), routerHandler.updateAvatar) module.exports = router

token的验证规则

module.exports = {
secretKey : 'sdfafsfds'
}

上面就是整个user部分的接口了包括登录注册,添加删除修改账号或者密码等,下面是我们的user的验证规则

// 2.2注册
// 2.2.1对表单数据验证,这里就不if else了直接用上joi来验证 joi要下最新版而且直接导入joi
const { number } = require('joi')
const joi = require('joi') const username = joi.string().alphanum().min(1).max(10).required()
// 错误点:正则{}里面的量词之间不能以空格隔开
const password = joi.string().pattern(/^[\S]{6,12}$/).required() // 3.2.2更新用户信息规则
const id = joi.number().integer().min(1).required()
const nickname = joi.string().required()
const email = joi.string().email().required() // 3.4.2更换头像规则
const avatar = joi.string().dataUri().required()
module.exports.schema_user_info = {
body : {
username,
password
}
} module.exports.schema_update_info = {
body : {
id,
nickname,
email
}
} module.exports.schema_update_pwd = {
// 3.3.2重置密码规则
body : {
oldPwd : password,
// --------------错误点这里就算是变量也要添加引号
newPwd : joi.not(joi.ref('oldPwd')).concat(password)
}
} module.exports.schema_updatee_avatar = {
body : {
avatar
}
}

6.

这个部分是对文章的名字和别名的增删改查的操作了,这里面的难点在于要去理解那个怎么来判断是否重名哪里

// 4.1.1文章分类列表函数
const { result } = require('@hapi/joi/lib/base')
const db = require('../mysql')
function getArticleList(req, res) {
// res.send('文章分类列表')
// 4.1.3获取文章数据
let selectArticleList = 'select * from article where is_delete = 0'
db.query(selectArticleList, (err, results) => {
if (err) return res.cc(err)
res.send({
status : 0,
msg : '获取文章分类列表成功',
data : results
})
})
} // 4.2.1新增文章分类
function addCates(req,res) {
// 4.2.3名字与别名是否重名
let selectDuplicate = 'select * from article where name = ? or alias = ?'
db.query(selectDuplicate, [req.body.name, req.body.alias], (err, results) => {
if(err) return res.cc(err)
if(results.length == 2) return res.cc('文章名字和别名已被占用')
if(results.length == 1 && results[0].name == req.body.name && results[0].alias == req.body.alias) return res.cc('文章名字和别名已被占用')
if(results.length == 1 && results[0].name == req.body.name) return res.cc('文章名字被占用')
if(results.length == 1 && results[0].alias == req.body.alias) return res.cc('文章别名被占用')
// 4.2.4实现文章分类新增
let addArt = 'insert into article set ?'
db.query(addArt, req.body, (err, results) => {
if(err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('新增文章失败')
res.cc('新增文章分类成功', 0)
})
})
} // 4.3.1根据idshanchuwenzhan
function deleteCate(req, res) {
// 4.3.3实现删除功能
let deleteId = 'update article set is_delete = 1 where id = ?'
db.query(deleteId, req.params.id, (err, results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('删除文章失败')
res.cc('删除文章分类成功', 0)
})
} // 4.4.1根据id获取文章分类
function requireArt(req,res) {
// 4.4.2
let selectArt = 'select * from article where id = ?'
db.query(selectArt, req.params.id, (err, results) => {
if (err) return res.cc(err)
if (results.length !== 1 || results[0].is_delete == 1) return res.cc('没有该文章')
res.send({
status : 0,
msg : '获取文章分类数据成功',
data : results[0]
})
})
} // 4.5.1根据id更新文章
function updateArt(req, res) {
// 4.5.2查看是否重名
// -----------------这里需要先将自己这一项排除出来
let selectIdDuplicate = 'select * from article where id != ? and (name = ? or alias = ?)'
db.query(selectIdDuplicate, [req.body.id, req.body.name, req.body.alias], (err, results) => {
if (err) return res.cc(err)
if (results.length == 2) return res.cc('文章名称和别名已被占用')
if (results.length == 1 && results[0].name == req.body.name && results[0].alias == req.body.alias) return res.cc('文章名称和别名已被占用')
if (results.length == 1 && results[0].name == req.body.name) return res.cc('文章名称已被占用')
if (results.length == 1 && results[0].alias == req.body.alias) return res.cc('别名已被占用')
let updateIdArt = 'update article set ? where id = ?'
db.query(updateIdArt, [req.body, req.body.id] , (err,results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('文章更新失败')
res.cc('更新分类信息成功', 0)
})
})
}
module.exports = {
getArticleList,
addCates,
deleteCate,
requireArt,
updateArt
}

这是路由模块,上面是路由的处理函数

// 4.文章类别管理
const express = require('express')
const router = express.Router()
const routerhanlder = require('../router_handler/article')
// 4.1获取文章分类列表
router.get('/cates',routerhanlder.getArticleList) // 4.2新增文章分类
const expressJoi = require('@escook/express-joi')
const {add_article_list, update_id_cate} =require('../schema/article')
router.post('/addcates',expressJoi(add_article_list),routerhanlder.addCates) // 4.3根据id删除文章
const {delete_id_cate} = require('../schema/article')
router.get('/deletecate/:id',expressJoi(delete_id_cate),routerhanlder.deleteCate) // 4.4根据id获取文章分类数据
router.get('/cates/:id',expressJoi(delete_id_cate), routerhanlder.requireArt) // 4.5根据id更新文章分类数据
const {update_id_Art} = require('../schema/article')
router.post('/updatecate',expressJoi(update_id_Art) ,routerhanlder.updateArt) module.exports = router

然后我们的规则

const joi = require('joi')

// 4.2.2新增文章规则
const name = joi.string().required()
const alias = joi.string().alphanum().required() // 4.3.2根据id删除文章 注意这个id是动态的而且是get请求,所以不再是body数据
const id = joi.number().integer().min(1).required()
module.exports.add_article_list = {
body : {
name,
alias
}
} module.exports.delete_id_cate = {
params : {
id
}
} module.exports.update_id_Art = {
body : {
id : id,
name : name,
alias : alias
}
}

7.

最后是我们的添加文章这个功能,就是往每一个刚才创建好的文章里面,添加新文章,直接看逻辑的实现吧

// 5.1.1发布文章函数
const path = require('path')
const db = require('../mysql')
function addCate(req, res) {
// 5.1.5因为上传表单无法用joi所以要单独规定
if (!req.file || req.file.fieldname !== 'cover_img') return res.cc('请上传图片')
// 5.1.6事先发布文章功能
const cateObj = {
...req.body,
cover_img : path.join('/uploads', req.file.filename),
pub_date : new Date(),
author_id : req.user.id
}
let addInsert = 'insert into articles set ?'
db.query(addInsert, cateObj, (err, results) => {
if (err) return res.cc(err)
if (results.affectedRows !== 1) return res.cc('发布文章失败')
res.cc('发布文章成功', 0)
}) } module.exports = {
addCate
}
// 1.4初始化路由相关文件夹 不光要给路由分装一个模块 里面的处理函数也要有一个模块
const express = require('express')
const { append } = require('express/lib/response')
const router = express.Router()
// 1.4.2导入路由处理函数
const routerHandler = require('../router_handler/user')
// 注册
// 2.2.2导入joi验证输入进来的是否合法
const expressJOI = require('@escook/express-joi')
const {schema_user_info} = require('../schema/user')
router.post('/reguser',expressJOI(schema_user_info), routerHandler.getReguser)
// 2.4登录
// 2.4.1添加语法规则,可以直接用注册的
router.post('/login',expressJOI(schema_user_info), routerHandler.getLogin)
module.exports = router

复习 - node.js(接口案例)的更多相关文章

  1. ajax请求node.js接口时出现 No 'Access-Control-Allow-Origin' header is present on the requested resource错误

    ajax请求node.js接口出现了如下的错误: XMLHttpRequest cannot load http://xxx.xxx.xx.xx:8888/getTem?cityId=110105&a ...

  2. node.js 接口调用示例

    测试用例git地址(node.js部分):https://github.com/wuyongxian20/node-api.git 项目架构如下: controllers: 文件夹下为接口文件 log ...

  3. node.js小案例_留言板

    一.前言 通过这个案例复习: 1.node.js中模板引擎的使用 2.node.js中的页面跳转和重定向 二.主要内容 1.案列演示:  2.案列源码:https://github.com/45612 ...

  4. node.js(小案例)_实现学生信息增删改

    一.前言 本节内容主要对小案例做一个总结: 1.如何开始搭建小项目 2.路由设计 3.模块应用 4.项目源码以及实现过程github地址: 项目演示如下: 二.主要内容 1.项目的关键性js源码: 项 ...

  5. Node.js接口避免重复启动

    众所周知,一个Node接口要是想被调用,得先在命令行中执行如下代码来启动接口 node base.js 但是一旦修改了base.js,就得重新执行这句命令 注:这里的base.js是我的node接口文 ...

  6. node.js 爬虫案例

    本案例是爬的一部小说,爬取并存在本地 使用了动态浏览器头部信息,和 动态ip代理, 这2个方式可以有效的伪装自己,不至于被反爬,然后拉黑,之前已有记录,浏览器头部信息,也记录的有, app.js im ...

  7. node.js(小案例)_使用mongodb对学生信息列表优化

    一.前言 1.这篇文章主要对上一篇案列在操作增删改的时候使用mongodb进行优化 2.项目源码(包含上):https://github.com/4561231/crud-express-node.g ...

  8. 深入浅出Node.js(一):什么是Node.js

    Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟Joyent获得企业资助,再到 ...

  9. 深入浅出Node.js(一):什么是Node.js(转贴)

    以下内容转自:http://www.infoq.com/cn/articles/what-is-nodejs/ 作者:崔康 [编者按]:Node.js从2009年诞生至今,已经发展了两年有余,其成长的 ...

随机推荐

  1. python3 爬虫6--requests的使用(1)

    1用requests进行网页请求与urlopen差不多,这里省略不说 2抓取网页的学习 import requests import re headers={'User-Agent': 'Mozill ...

  2. 对原型链的理解?prototype上都有哪些属性?

    在js里,继承机制是原型继承.继承的起点是 对象的原型(Object prototype). 一切皆为对象,只要是对象,就会有 proto 属性,该属性存储了指向其构造的指针. Object prot ...

  3. 什么是Java序列化,如何实现Java序列化?或者请解释Serializable接口的作用?

    象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传输对象,对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久保存在磁盘上,通过网络将这种二进制流传输到另 ...

  4. springcloud断路器作用?

    当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应 当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)断路器有完全打开状态:一段时间内 达到一定的 ...

  5. 如何建立一个JDBC程序?

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sq ...

  6. Jedis 与 Redisson 对比有什么优缺点?

    Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令 的支持:Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能 ...

  7. .Net Core:Docker无法拉取mcr.microsoft.com相关镜像解决办法

    今天在教同事Docker简单部署Asp.Net Core项目,pull镜像时突然出现下图中的错误: 因为微软在 2018 年五月之后,只会将相关镜像打包发布到 MCR 上.但是 MCR 对国内用户不太 ...

  8. Java/C++实现策略模式---旅游出行方式

    旅游的出行方式有乘坐飞机旅行.乘火车旅行和自行车游,不同的旅游方式有不同的实现过程,客户可以根据自己的需要选择一种合适的旅行方式. 类图: Java代码: public class Person { ...

  9. Python使用逻辑回归估算OR值

    第一种是统计学方法,需要用到 statsmodels包 statsmodels是统计和计量经济学的package,包含了用于参数评估和统计测试的实用工具 第二种是机器学习,需要使用sklearn中的L ...

  10. 抽象方法不能为private,final或者static,为什么?

    4)抽象方法不能为private,final或者static, native, synchrozied为什么?[新手可忽略不影响继续学习]马克-to-win:抽象方法的最实质的意义在于被未来的子类覆盖 ...