三阶段-node
三阶段: 两个月 node express mvc项目结构搭建 1 vue (移动端m站 电商) 3 react 2周 + 2-3天
微信(小程序 公众号 app 查漏补缺(大屏可视化 echarts 地图 ))
git remote add origin(地址) git push origin master
npm网址:https://www.npmjs.com/
功能:管理项目、管理项目中依赖的资源包
// 初始化 创建一个package.json npm init [-y/--yes] /* 安装包 注意区分 环境 production 生产环境,生产环境的包项目上线后还需要这个包 如 jquery development 开发环境 辅助项目开发,上线后不需要 如 gulp-babel 安装包 一定注意区分开发环境和生产环境 */ npm install 包名[@版本号][--save/--save-dev][-g] // eg 简写 npm i 包 [-S/D] // i install 简写 -S --save简写 -D --save-dev简写 npm install // 当我们拉取代码,是没有node_modules目录的,执行npm install自动安装项目的所有的依赖包(自动读取package.json文件) npm run 脚本名称 npm uninstall 包[-g] /* 装一个包,版本错误 需要先卸载再安装 */ npm update 包名 // 更新版本 npm info 包名 // 查看包信息 npm publish // 查看包的所有历史版本信息
npm 淘宝源
-
使用cnpm
-
npm install cnpm -g --registry=https://registry.npm.taobao.org // npm命令 由npm 改为cnpm 就行 cnpm install 包名
- nrm 切换源
-
npm i nrm -g // 全局安装 nrm ls //查看可用源 nrm use 源 // 切换源
npm i yarn -g yarn init yarn add 包 // 默认安装到生产还环境 npm i 包 -S yarn add 包 --dev // 安装到开发环境 yarn remove 包 // 移除一个包 yarn add 包 --global // 全局安装 yarn // 安装项目所以依赖 npm install yarn 脚本名 // 执行脚本 npm run 脚本
时常要关注的计算机网站:
commonjs
-
避免了 变量污染问题(每个模块有自己的作用域)
-
按需加载 不同 模块(js 运行效率更高 在 js 中动态引入)
const fs = require("fs");
fs.readFile();
const 模块名 = require("模块名");
总结: 系统模块和第三方模块,使用时直接 require 写模块名(不要写路径)
注意:当我们引入一个模块 直接引入模块名时,优先找全局模块,如果没有查找 node_modules 也没有报错
// a.js const fn = () => { console.log("我是一个函数"); }; fn(); // b.js require("./a.js"); /* 1,直接require即可不需要使用变量接收模块 (没有向外导出模块) 2,即使是同一目录下,也需要 加 路径 ./否则会解析成全局模块或者 node_modules中的第三方模块 */
- 一个文件 导出多个接口
// a.js exports.a = 100; exports.b = [1,2,3,4]; exports.c = ()=>{ console.log('我是一个函数'); } // b.js引入 // 全部引入 const obj = require('./a.js') // obj是一个对象 三个属性 分别是 a/b/c // 解构赋值 按需引入 const { a,c } = require('./a.js') // 定义两个变量a,c值是 a.js中a模块和c模块的值
- 一个文件只能向外导出一个接口
// a.js module.exports = 值 // 引入 b.js const 变量 = require('./a.js') /* 注意: 一个文件只能出现一次module.exports如果出现多次module.exports那么下面会覆盖上面的 一个文件即出现了 module.exports 也出现了 exports 那么以module.exports为准 */
__dirname // 当前文件所在目录的绝对路径 __filename // 当前文件所在的绝对路径 process.cwd() // 当前进程运行所在的绝对路径(js在哪个目录下运行的) /* 绝对路径: 如果有服务器环境 那么 (绝对路径)根目录是服务器监听目录(phpstudy apache监听 WWW目录) 如果没有服务器环境。那么绝对路径根目录是 盘符 注意: / 写在路径最前面 代表绝对路径根目录 */
操作路径 path.join() 方法会将所有给定的 path 片段连接到一起(使用平台特定的分隔符作为定界符),然后规范化生成的路径。
长度为零的 path 片段会被忽略。 如果连接后的路径字符串为长度为零的字符串,则返回 '.',表示当前工作目录。
path.join('/目录1', '目录2', '目录3/目录4', '目录5', '..');
// 返回: '/目录1/目录2/目录3/目录4'
path.join('目录1', {}, '目录2');
// 抛出 'TypeError: Path must be a string. Received {}'
// 结合__dirname
path.join(__dirname,'a','b')
path.resolve("a","b","c")
// 当前目录下
// d://当前目录/a/b/c
path.resolve("a","/b","c")
// d://b/c
path.extname(path) 得到一个路径 指向文件的后缀名
http
const http = require('http');
http.get('http://www.tupianzj.com/meinv/mm/me/meituwang/',(res) => {
res.setEncoding('utf8');
let rawData = '';
res.on('data',(chunk) => {
rawData += chunk;
}) //on在这里是用来监听
res.on('end',() => {
console.log(rawData);
});
}.on('reeor',(e) => {
console.log(`出现错误:${e.message}`);
})
http的简易爬虫-爬网页的src
const http = require('http');
const cheerio = require('cheerio');
http.get('http://www.tupianzj.com/meinv/mm/me/meituwang/',(res) => {
res.setEncoding('utf8');
let rawData = '';
let arr = [];
res.on('data',(chunk) => {
rawData += chunk;
}) //on在这里是用来监听
res.on('end',() => {
const $ = cheerio.load(rawData);
$('img').each((i,el) => {
arr.push($(el).attr('src'))
})
console.log(arr)
});
}.on('reeor',(e) => {
console.log(`出现错误:${e.message}`);
})
espress框架
nodejs: express koa2(基于express封装)
egg.js(mvc框架)
const express = require('express');
const app = express();
// 新增一个路由
app.get('/a', (req,res)=>{
res.send('你好啊');// 向前端返回数据可以是字符串或者对象
})
app.listen(3000, ()=>{
console.log('start at port 3000')
})
npm i nodemon -g // 运行js nodemon js文件
后端写数据接口(一个路由 请求方式 发送什么参数,给什么数据) 接口文档:
项目流程:(产品) 立项 -- 需求收集 -- 得到需求(整理) -- 产品经理 (设计原型) UI 设计图 -- 项目(后端+前端)设计数据库(接口文档)
前端拿到设计图要写页面(mock接口 接口文档)
后端写接口
前后端联调(联合调试)
测试 上线 迭代
c/s b/s
- get请求的参数解析
req.query // 自动序列化为对象 // username=小明&pwd=123456 { username: "小明", pwd: 123456 }
- post 请求参数 (请求体 request body)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded') //设置响应头
// x-www-form-urlencoded /* 机器(浏览器和服务器)传输数据 字符串 不能传多字节 key=v&key=v 且中间多字节 会转换成 % 加密格式 */
formdata 对象可以传(urlencoded)
const middleware = (req,res,next)=>{ req.a = 10; next(); }
使用中间件
// 作为全局中间 会拦截所有的请求 app.use(中间件) // 作为局部中间件 拦截特定url app.use(url,中间件)
npm i body-parser -s
引入
const bodyParser = require (' body-parser ')
const express = require('express');
const bodyparser = require('body-parser');
const app = express();
app.use(bodyparser.urlencoded ({
extendned: false
}));
app.use(bodyparser.json())
app.post('/b',(req,res) => {
console.log (req.body);
res.send ('我是一个post请求')
});
app.listen(3000, ()=>{
console.log('start at port 3000')
})
登录小案例
const express = require('express');
const bodyparser = require('body-parser');
cosnt user = {
username: '小明',
pwd: 123456
}
const app = express();
app.use(bodyparser.urlencoded ({
extendned: false
}));
app.use(bodyparser.json())
app.post('/login',(req,res) => {
if (username === user.username) {
if (parseInt(pwd) === parseInt(user.pwd)) {
res.send('登录成功')
}else {
res.send('账户或密码不正确')
}
}else {
res.send('没有当前用户')
}
});
app.listen(3000, ()=>{
console.log('start at port 3000')
})
// routes/home.js const router = require('express').Router(); router.get('/home', (req,res)=>{ res.send('我是首页') }) router.post('/home', (req,res)=>{ res.send('我是首页的post请求') }) module.exports = router; // 在 index.js 入口函数 中引入并使用中间件即可 const homeRouter = require('./routes/home') app.use(homeRouter);
app.use('/static', express.static(path.join(__dirname,'public')))
// 安装 npm i ejs -S // 设置模板(views)的目录 app.set('views', path.join(__dirname,'views')) // 设置使用哪个模板引擎 app.set('view engine', 'ejs') // 路由中使用 渲染哪个模板(ejs) res.render('模板名字')// render第二个参数携带的变量可以在 模板中使用 // 输出 <%= 表达式 %> /* 表达式 js环境 需要使用了变量 必须是 render携带过来的变量 */ <%%> // 可以写任意js 一般写循环或者if分支结构 /* <ul> <% for(var i=0;i<arr.length;i++){ %> <li><%= arr[i] %></li> <% } %> </ul> */ <%- content %> // 渲染富文本数据 转义成html 谨慎使用 有可能 xss攻击 // 引入公共模板 <%- include('head') -%>
const router = require('express').Router();
const multer = require('multer');
const path = require('path')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads')
},
filename: function (req, file, cb) {
// 自定义文件名的
/* console.log(file);
console.log(path.extname(file.originalname)) */
// 后缀名
const extname = path.extname(file.originalname);
cb(null, file.fieldname + '-' + Date.now()+extname);
}
})
const upload = multer({ storage: storage })
router.get('/upload', (req,res)=>{
res.render('upload');
})
router.post('/upload', upload.single('img') ,(req,res)=>{
res.send('上传成功');
})
module.exports = router;
// 在index文件中引入并使用
const uploadRouter = require('./routes/upload');
app.use(uploadRouter);
非关系型数据 存储数据格式 就是json mongodb redis
关系型数据:mysql oracle
对比
关系型 非关系型
数据库(database) (数据仓库) 数据库(database)
表 (table) collection 集合 [{},{},{}]
行 row document 文档 json
列 字段 col key
mongod [--dbpath D:\h5-2008\node\data] // dbpath指定mongodb数据库的存储目录 如果不指定 默认是盘符下的 data/db
show dbs 查看有哪些数据库 use 数据库 切换到这个数据库 show collections 查看当前数据库下 有哪些 集合 (前提 你得先切换到目标数据库) 一下 所有的操作 都需要切换到 目标数据库才能执行 db.createCollection("名字") 创建一个集合 db.集合名.drop() 以上命令 都不重要(这些操作 我们一般会在可视化软件中操作) 下面 增删改查 才是重点
关系型数据库
数据库
表
行
字段
db.集合名.find()
db.集合名.find().pretty()
db.age.find({name:"wscats"})
操作 语法 示例 等效语句 相等 {:} `db.age.find({"name":"wscats"}).pretty()` where name = 'wscats' 小于 {:{$lt:}} `db.age.find({"likes":{$lt:50}}).pretty()` where likes < 50 小于等于 {:{$lte:}} `db.age.find({"likes":{$lte:50}}).pretty()` where likes <= 50 大于 {:{$gt:}} `db.age.find({"likes":{$gt:50}}).pretty()` where likes > 50 大于等于 {:{$gte:}} `db.age.find({"likes":{$gte:50}}).pretty()` where likes >= 50 不等于 {:{$ne:}} `db.age.find({"likes":{$ne:50}}).pretty()` where likes != 50
在find()方法中,如果通过使用,将它们分开传递多个键,则mongodb将其视为AND条件。 以下是AND的基本语法
寻找_id为1并且name为wscats的所有结果集
db.age.find( { $and: [ {"_id": 1}, {"name": "wscats"} ] } )
在要根据OR条件查询文档,需要使用$or关键字。以下是OR条件的基本语法
寻找name为corrine或者name为wscats的所有结果集
db.age.find( { $or: [ {"name": "corrine"}, {“name“: "wscats"} ] } )
db.age.find({ $or: [{ "title": "wscats" }, { $and: [{ "title": "corrine" }, { "_id": { $lte: 5 } }] }] })
文档的数据结构和JSON基本一样。 所有存储在集合中的数据都是BSON格式。 BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON。
要将数据插入到mongodb集合中,需要使用mongodb的insert()或save()方法。
db.集合名.insert(document)
比如我们可以插入以下数据
db.wscats.insert({ title: 'MongoDB Tutorials', description: 'node_tutorials', by: 'Oaoafly', url: 'https://github.com/Wscats/node-tutorial', tags: ['wscat','MongoDB', 'database', 'NoSQL','node'], num: 100, })
也可以支持插入多个,注意传入的是数组形式
db.wscats.insert([{ _id: 100, title: ‘Hello’ },{ _id: 101, title: ‘World’ }])
db.wscats.save({ _id: 111, title: 'Oaoafly Wscats', })
db.age.update({ 'title': 'wscats' }, { $set: { 'title': 'corrine', 'age': 12 } })
默认情况下,mongodb只会更新一个文档。要更新多个文档,需要将参数multi设置为true,还可以配合find方法里面的各种复杂条件判断来筛选结果,然后更新多个文档
寻找所有title为wscats的值,并且更新值title为corrine和age为12
db.age.update({ 'title': 'wscats' }, { $set: { 'title': 'corrine', 'age': 12 } }, { multi: true })
db.age.save({ '_id':3, 'title': 'wscats' })
db.age.remove({ '_id':3 })
建议在执行remove()函数前先执行find()命令来判断执行的条件是否正确
如果你只想删除第一条找到的记录可以设置justOne
db.age.remove({...},1)
全部删除
db.age.remove({})
db.age.find().limit(数量)
db.age.find().limit(数量).skip(数量) //skip()方法默认值为0 current: 当前页 pageSize:一个多少条 10 1 0 9 2 10 19 3 20 29 db.age.find().limit(pageSize).skip((current-1)*pageSize)
所以我们在实现分页的时候就可以用limit来限制每页多少条数据(一般固定一个值),用skip来决定显示第几页(一个有规律变动的值)
db.集合名.find().sort({键值(属性值):1})
db.age.find().sort({ "_id": -1 })
内部写的是mongodb 原生的sql语法 为什么不推荐:mongodb是非关系型数据库,对于数据不做验证,在实际开发过程中是可取的 // Requires official Node.js MongoDB Driver 3.0.0+ var mongodb = require("mongodb"); var client = mongodb.MongoClient; var url = "mongodb://localhost:27017/"; client.connect(url,{useUnifiedTopology:true}, function (err, client) { if(err){ client.close(); } var db = client.db("test"); var collection = db.collection("stu"); var query = { age:{ $gt:20 } }; var cursor = collection.find(query); cursor.forEach( function(doc) { console.log(doc); }, function(err) { client.close(); } ); // Created with Studio 3T, the IDE for MongoDB - https://studio3t.com/ });
总结:
mongodb
数据库(相当于表) document (相当 collection 集合于 行) key (键) db.stu.find({ }) db.stu.insert([{}]) db.stu.update( { _id:1 }, { $set: {} } ) db.stu.remove({}) // 查询 .sort({ key: -1 }) .limit().skip() db.xxx.find().sort({_id:-1}).limit(pageSize).skip((current-1)*pageSize)
mongod的缺点:mongodb原生语法很宽松,对于集合不会做任何验证
nodejs库 封装好很多的方法 用于连接或者操作数据库 对于mongodb 数据库中的数据做了类型的验证 *** typejs 超集 http://www.mongoosejs.net/docs/ 中文文档 连接: 两个 重要概念 Schema 计划 映射 了 一个 collection 里面所有的字段,对于字段做了 类型验证 const mongoose = require("mongoose") const { Schema } = mongoose; 定义个schema const cateSchema = new Schema({ cateName:{ type:String, required:true }, cateIcon:String, pid:{ type:Number, required:true }, showHome:{ type:Number, default:1 } }); model collection的实例(collection),定义时需要传入 他的 Schema 下 提供了很多的方法 用于操作 sql语句 定义model const cateModel = mongoose.model("qf_cate",cateSchema) 命名最好使用下划线命名法 model下的方法
操作数据库前,做了 验证
npm i mongoose //命令行下载mongoose const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/test',{ useNewUrlParser: true, useUnifiedTopology: true }); var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function() { // we're conected! console.log('mongodb上线了') }); /* schema 理解为 集合(collection) 结构, 定义一个集合的字段以及字段类型 (操作集合如增加一条数据,都会经过schema验证,验证通过允许操作,否则报错) */ // 学生表结构 const stuSchema = new mongoose.Schema({ a: String, b: { type: Number, required: true }, c: { type: String, default: '我是默认值' }, d:[String, Number] }) // 数据类型有 String Number Date Buffer Boolean Mixed ObjectId Array // 创建表 model const stuModel = mongoose.model('集合名', stuSchema); stuModel.insertMany().then() stuModel.find() .findOne() stuModel.update() stuModel.remove() .sort().limit().skip()

浙公网安备 33010602011771号