其实复习一次的作用真实太大了,真的,自从上次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. sqlserver下载地址及密匙

    SqlServer 2017 下载地址及密钥 下载地址: ed2k://|file|cn_sql_server_2017_developer_x64_dvd_11296175.iso|17697771 ...

  2. XMLBeanFactory?

    最常用的就是 org.springframework.beans.factory.xml.XmlBeanFactory ,它根据XML文件中的定义加载beans.该容器从XML 文件读取配置元数据并用 ...

  3. 启动一个线程是调用 run()还是 start()方法?

    启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态, 这意味着它可以由 JVM 调度并执行,这并不意味着线程就会立即运行.run()方 法是线程启动后要进行回调(callb ...

  4. vue项目给less传递参数,出现 Invalid options object. Less Loader has been initialized using an options object that does not match the API schema.

    vue-cli创建的项目,想使用less-loader的全局变量配置,但是配置(vue.config.js文件)项出现 error in ./src/components/BookFooter.vue ...

  5. Spring Cloud第一次请求报错问题

    一.原因 我们在使用Spring Cloud的Ribbon或Feign来实现服务调用的时候,第一次请求经常会经常发生超时报错,而之后的调用就没有问题了.造成第一次服务调用出现失败的原因主要是Ribbo ...

  6. scrapy框架初识及使用

    一.什么是Scrapy? Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍.所谓的框架就是一个已经被集成了各种功能(高性能异步下载,队列,分布式,解析,持久化等) ...

  7. java中的VO、PO、BO、DAO、POJO

     针对java工程里的各种带O的对象,进行分析,了解各自的作用. PO: persistent object,持久对象.与数据库里表字段一一对应.PO是一些属性,以及set和get方法组成.一般情况下 ...

  8. 序列化多表操作、请求与响应、视图组件(子类与拓展类)、继承GenericAPIView类重写接口

    今日内容概要 序列化多表操作 请求与相应 视图组件 内容详细 1.序列化多表操作 模型类 models.py中 # 新建django项目 # 创建表 模型类models.py中: from djang ...

  9. ros中关于节点、话题、服务以及自定义消息等在终端中的常用命令

    以下面的计算力图说明 节点相关常用命令 在终端中查看项目中有哪些节点命令:rosnode list 有了节点信息想要查看节点中到底发布订阅了哪些话题,作为服务端服务类型或者作为客户端需要的服务类型以上 ...

  10. 【转】ng-class的用法

    原文出处:https://segmentfault.com/a/11... 在开发中我们通常会遇到一种需求:一个元素在不同的状态需要展现不同的样子. 而在这所谓的样子当然就是改变其css的属性,而实现 ...