盘符: # 进入某个盘符
cd 目录 # 进入某个目录
cd .. # 回到上一级目录
dir # 查看当前文件夹中的文件和文件夹
tree # 查看当前文件夹中的所有文件和文件夹包括子文件夹及其文件,树状结构
cls # 清屏
ipconfig # 查看当前电脑的网管信息
systeminfo # 查看当前电脑的配置信息
md 文件夹名 # 新建文件夹 make dir directory
rd 文件夹名 # 删除文件夹
xcopy 文件夹 新文件夹名 # 复制文件夹,并起新的名字
type nul> 文件名 # 新建文件
copy 文件名 新文件名 # 复制文件,并起新的名字
echo 内容 > 文件名 # 给文件中写入内容
move 文件路径 新的路径 # 将文件移动到新的路径
ren 文件名 新的文件名 # 将文件重命名
del 文件名 # 删除一个文件
#上下键操作之前的命令
tab:#可以切换文件
# 安装node后
node:#进入环境 node交互解释器
node 文件名.js#运行js文件
#ctrl+c:退出环境
选择JavaScript的原因:
直接在百度上搜node.js然后进入官网下载,下载左边的旧版,不容易出错
直接傻瓜式安装,路径可改可不改,建议在c盘,提高node的运行速度。
在cmd
里面执行node --version
或node -v
node -v #然后回车,在任何文件夹下的cmd都能检测,结果返回版本号即安装成功
即交互解释器:就是js
运行引擎、就是安装node后的命令行
命令行输入: node
进入交互解释器
注意:安装前,一定要卸载完全node
教程网站:https://www.cnblogs.com/dreamsqin/p/10885082.html
下载模块:https://github.com/coreybutler/nvm-windows/releases
问题解决:https://www.cnblogs.com/aer2005/p/11548550.html
node包含3中模块:内置模块,自定义模块,第三方模块。
自定义模块:自己定义封装的方法函数,或者对象的js文件。
第三方模块:下载网上别人封装的方法函数或对象。
npm -v#返回版本号即安装成功
npm install npm -g
npm i -g nrm
npm config get prefix #查看安装路径
nrm --version
nrm ls # 用来检测哪个地址下载速度快一些,当前使用地址前面会带*
现在有很多网址,将常用的工具放上去,供人们下载,我们将这些网址叫做镜像源。
测试出来的结果:镜像源名称 ---- 网速
,我们挑选网速最快的镜像源地址使用:
nrm use taobao # 将下载地址切换成taobao的镜像源
$ cnpm sync connect
#cnpm和npm使用是一样的,是国内的npm
npm install -g cnpm --registry=https://registry.npm.taobao.org#或者
npm config set registry=https://registry.npm.taobao.org
#注意,powershell无法执行修改vscode默认终端:F1搜索select选中其中的终端默认选项,然后修改
npm config get registry
npm init # 创建一个当前文件目录下的packjson.js管理环境。
npm init --yes # 直接选用默认配置
npm install 包名@版本号 # 下载一个包到当前命令行所在目录,生产开发都装,版本号不写默认最新
npm i 包名@版本号 #下载指定的版本
npm install -g 包名 #全局安装一个包
npm install --global 包名#同上
npm install --save #记录生产环境所需的模块,代码错误只会终止执行,构建#dependencies
npm install --save-dev #开发环境,代码错误明确指出错误。开发#devDependencies
npm update 包名 # 升级依赖包
其中install可以简写为i
如出现报错:
npm err! Error: connect ECONNREFUSED 127.0.0.1:8087
处理报错:
npm config set proxy null
npm list -g #查看全局安装的模块
npm list grunt #参看某个模块的版本
npm root 模块 #查看模块安装路径
npm uninstall 模块名或包名 #卸载命令
npm ls 包名 #查看卸载的包是否还存在,查看包的信息
npm cache verify #清除卸载缓存文件。
npm cache clean --force #清除缓存文件
package.json
package.json
npm init #创建或生成package.json文件(模块),初始化(会将一下载的模块记录)
#然后安装Package.json 属性填写对应值
npm init -y#使用默认配置
package.json
属性mode_modules
这个文件夹层级深,文件冗余,不容易复制移动
拷贝项目的时候不需要拷贝node_modules,只需要拷贝一个包的列表文件、package.json文件,到自己电脑上下载,不会出现文件丢失的情况,且是自动下载
步骤:⭐
npm i
自动下载npm update 模块名 #加-g就是变成全局更新npm outdate 模块名 #查看本标信息
npm search 模块名
const http = require('http');
在package.json
的文件夹的script
属性里可以添加自定义属性
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"aa":"echo 6666",//这是自定义属性
"startJs":"node ./test2.js"//自定义属性
},
然后再cmd里运行
npm run-script aa#或者npm run startJS
然后开始运行这些属性对应的属性值里的字符串。
yarn
更快的安装管理npm i yarn -g
1. npm install [-args] [<@scope>/]<name>[@<version range>]
# 安装第三方依赖包,例如:npm install --global @babel/[email protected]
2. npm uninstall [-args] [<@scope>/]<name>[@<version range>]
# 卸载模块,例如:npm uninstall jquery --save-optional,卸载可选阶段的依赖里的jquery
3. npm update [-g] [<pkg>] # 更新模块。
4. npm outdated [[<@scope>/]<pkg>] # 检查模块是否已经过时。
5. npm ls [[<@scope>/]<pkg> ...] # 查看安装的模块。
6. npm init [-f|--force|-y|--yes]
# 在项目中引导创建一个package.json文件。
# 安装包的信息可保存到项目的package.json文件中,以便后续的其它的项目开发或者他人合作使用。
7. npm root [-g] # 查看包的安装路径
8. #管理npm的配置路径有关的命令
npm config set <key> <value> [-g|--global]
npm config get <key>
npm config delete <key>
npm config list
npm config edit
npm get <key>
npm set <key> <value> [-g|--global]
9. npm cache verify # 清理缓存,如果安装莫名报错可以考虑清空缓存。
10. npm start [-- args] # 启动某个脚本指令
# 该命令写在package.json文件scripts的start字段中
# "scripts": { "start": "gulp -ws" }
# 可以自定义命令来配置一个服务器环境和安装一系列的必要程序,如此时在cmd中输入npm start命令相当于执行gulpfile.js文件自定义的watch和server命令。
11. npm stop [-- args]: # 停止脚本。
12. npm restart: # 重启脚本。
13. npm publish: # 发布自己的模块到仓库。
14. npm version: # 查看版本。
script
标签内运行.js
后缀文件下运行,通过
引入运行.js
文件之间如何导出引入,形成模块化导出
let x={"name":"jack"};
let addX=function(v){
x.age=v;
return x;
};
module.exports.x=x;
module.exports.addX=addX;
//module.exports后面想咋写就咋写,但最后导入时都合并成一个对象了
引入
let obj=require("./a.js");
let abj=require("./a.js");
console.log(obj.x);
console.log(obj.addX(5));
console.log(abj.addX(5));
//此时的将导出的对象合并成一个对象了。 且可以不同变量引入。
特点:不需要在服务器环境下运行,可以进入文件之间执行
必须在服务器上才能执行,这是es6的通病⭐
导出
// a.js文件
let a=50;
export var num = 100;
export {a};
export {a as b};//将a赋值给b,将b导出
导入
import {num} from './a.js'; //导入 num
import {a} from './a.js'; //导入 a
import {b} from './a.js'; //导入 b, 其实还是a
inport {a as c} from './a.js'; //导入 a赋值给c
import {num,a,b} from './a.js'; //导入多个变量
import * as d from './a.js'; //导入整个a.js文件,d.num, d.a, d.b
import "./a.js"; //直接导入a.js文件。
console.log(num);
console.log(d.b);
特殊
//a.js
let a=50;
exprot default a;//也可以直接导出变量。
// c.js
exprot default "Rose";//默认直接导出,直接将值导出
// d.js
import name from './c.js'
import age from './a.js'
let ac = { name, age };
export {ac as default, name, age };//变形写法
export { default as moment } from 'moment'; // 导出重定向
// e.js
export { a: 'a', b: "b" }
//b.html
<script>
import v from "./a.js"; //此时导出的变量自定义, v = 50
import c from './c.js'; // 此时c = 'Rose'
import d from './d.js'; // 此时d = 60
import {default as m} from './e.js';//变形后的导入写法
import { moment } from './d.js'
console.log(m);
</script>
标准回调函数:它有两个参数,第一个参数为err,第二个参数为data,err是错误信息,data则是返回的数据
function callback(err, data) {}
console.log(__dirname, "打印当前文件绝对路径");
console.log(__filename, "打印当前文件绝对路径");
根据路径
获取文件名称:console.log(path.basename(fileName), path.basename(fileName, '.js'))
获取文件所在路径:console.log(path.dirname(fileName))
获取文件后缀名:console.log(path.extname(fileName))
判断是否为绝对路径:console.log(path.isAbsolute(fileName))
路径字符串拼接+容错处理,会校验入参
console.log(path.join('/foo', '/src', '/test'))
返回路径信息对象
var fileInfo = path.parse(fileName)
// 对象包含一下信息
fileInfoObj = {
root: "/", // 根路径
dir: "/src/demo", // 文件所在路径
base: "test.js", // 文件全称
ext: ".js", // 文件后缀
name: "test" // 文件名称
}
将路径信息对象转路径:path.format(fileInfo)
获取跳转路径:var jumpPath = path.relative('/src/from/test', '/src/to/test')
获取跳转后路径:console.log(path.resolve('/src/from/test', jumpPath))
相对路径转绝对路径:path.resolve(__dirname, '../dist');
测试当前文件是否能够操作
fs.access( path, err => {
if(err) return console.log(err);
else { // 执行其他。}
}
)
创建一个文件(覆盖写入/清空文件) ——
fs.writeFile(path, 写入内容, [数据格式], callback)
获取路径下全部文件/文件夹名称名称 —— fs.readdir(path, callback)
修改(裁剪)一个文件名称 —— fs.rename(oldPath, newPath, callback)
删除一个文件 —— fs.unlink(path, err => console.log(err))
判断是否为文件 —— fs.stat
const fs = require('fs'); // 判断是否为文件
function isTheFile(path) {
fs.stat(path, (err, stats) => {
if (err) return console.log(err);
if (stats.isFile()) {
console.log('是文件');
return "file";
}
if (stats.isDirectory()) {
console.log("是文件夹");
return "directory";
}
})
}
复制一个文件 —— fs.copyFile(oldPath, newPath, callback)
读取文件内容 — — fs.readFile(path, (err, data) => { console.log(data) })
默认读取二进制数据流,通过:data.toString('utf8')
或者:fs.readFile(path, 'utf8', (err, data) => { console.log(data) })
后加写入文件内容 —— fs.appendFile(path, 写入内容, callback)
删除(清空、修改)文件内容 — — fs.writeFile(path, '修改内容,可为空', callback)
同步须有异步api后加Sync
判断是否为文件 —— fs.stat
const fs = require('fs'); // 判断是否为文件
function isTheFile(path) {
fs.stat(path, (err, stats) => {
if (err) return console.log(err);
if (stats.isFile()) {
console.log('是文件');
return "file";
}
if (stats.isDirectory()) {
console.log("是文件夹");
return "directory";
}
})
}
读取文件/文件夹名称
同步:const files = fs.readdirSync(‘./path’);
异步:fs.readdir('./path', callback)
同步直接赋值获取文件夹名称数组,异步通过回调函数获取,异步能抛出错误不阻塞。
创建一个文件夹 —— fs.mkdir(path, err => console.log(err))
修改(裁剪)一个文件夹名称 —— fs.rename(oldPath, newPath, callback)
不会因文件夹里面含有内容就不能修改或裁剪
删除一个空文件夹 —— fs.rmdir(path, err => console.log(err))
删除一个非空文件夹 —— 需要进行递归处理
// 部分api见下文
const fs = require('fs');
const path = require('path');
/*
* 删除目录、子目录,及其中的文件
* @param dirPath {String} 要删除的目录
*/
function deleteDirectory(dirPath) {
return new Promise((resolve, reject) => {
fs.access(dirPath, err => { // 测试当前文件是否能够操作
if (err) reject(err); // 抛出错误
fs.readdir(dirPath, (err, files) => { // 读取地址下面全部文件夹
if (err) reject(err); // 读取文件夹列表,出现错误抛出错误
Promise.all(files.map(file => {
let filePath = path.join(dirPath, file)
return new Promise((resolve, reject) => {
fs.stat(filePath, (err, stats) => {
if (err) {
reject(err);
} else if (stats.isFile()) { // 如果是文件
fs.unlink(filePath, err => {
if (err) reject(err)
else resolve()
})
} else if (stats.isDirectory()) { // 如果是文件夹
// resolve(resolve())是会通过的
resolve(deleteDirectory(filePath)) // 递归调用函数
}
})
})
})).then(()=>{
// 如果所有上面的全部执行通过,或者files为空,则为空文件夹
// 如果只是空文件夹,抛出resolve, 然后执行then的回调函数
fs.rmdir(dirPath, err=>{ // 删除空文件夹
if(err) reject(err);
resolve()
})
}).catch(reject);
})
})
})
}
module.exports = deleteDirectory; // 抛出删除函数
复制一个文件夹
const fs = require( 'fs' );
/*
* 复制目录、子目录,及其中的文件
* @param src {String} 要复制的目录
* @param dist {String} 复制到目标目录
*/
function copyDir(src, dist) {
fs.access(dist, function(err) {
if (err) fs.mkdirSync(dist); // 目录不存在时创建目录
_copy(null, src, dist); // 然后调用函数,有错报错
});
function callback(err) { err && console.log(err) }
function _copy(err, src, dist) {
if (err) return callback(err); // 有错报错
fs.readdir(src, function(err, paths) {
if (err) return callback(err); // 有错报错
paths.forEach(function(path) {
const _src = src + '/' +path;
const _dist = dist + '/' +path;
fs.stat(_src, function(err, stats) {
if (err) return callback(err); // 有错报错
if(stats.isFile()) fs.copyFileSync(_src, _dist); // 判断是文件还是目录
if(stats.isDirectory()) copyDir(_src, _dist, callback); // 当是目录是,递归复制
})
})
})
}
}
module.exports = copyDir;
function dirTree(pathParams, index = 0) { // 深度搜索
let baseName = path.parse(pathParams).base;
if(fs.statSync(pathParams).isDirectory()){ // 是文件夹
console.log(markT(index), baseName)
let dirLis = fs.readdirSync(pathParams);
index++; // 进入下一级
dirLis.forEach(value => {
dirTree(path.join(pathParams, value), index);
})
}else{ // 是文件
console.log(markT(index), baseName)
}
//生成等比的文件间隔符
function markT(index){
if(index === 0) return '你要读取的文件夹:'
let str = '';
for(let i=0; i < index; i++){
str += ' |---'
}
return str;
}
}
dirTree(pathParams);
使用第三方模块:node-xlsx
在npmjs里面搜索node-xlsx
使用
将json转二维数组,然后可以使用xlsx.build
可以生成xls/xlsx
文件的二进制码
const data = [
[1, 2, 3],
[true, false, null, 'sheetjs'],
['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
['baz', null, 'qux']
];
const options = {
'!cols': [
{ wch: 6 },
{ wch: 7 },
{ wch: 10 },
{ wch: 20 }
]
};
// 转换为xls文件二进制码
var buffer = xlsx2json.build([{name: "mySheetName", data: data}], options);
fs.writeFile('data.xlsx', buffer, 'binary', (err) => {})
使用xlsx.parse
可以读取xls/xlsx
文件,将数据读取为二维数组
再将二维数组转json即可
实现了xls
文件写入,读取,修改。其他的还是文件基本操作(复制,修改名称)
使用内置child_process模块
调用本地应用程序
打开浏览器或其他文件
const cp = require('child_process');
cp.exec('start http://127.0.0.1:8889/'); // 自动打开默认浏览器
cp.exec('start 音频文件地址'); // 自动打开默认播放器播放音频
// 注意:文件地址上下级用 \\ 用双不用单,其他文件方式相同
// 同时exec里面执行的是shell脚本命令
运行本地应用程序
const cp = require('child_process');
cp.execFile('F:\\软件包\\Dict\\YoudaoDict.exe', (err, data) => {
err && console.log(err);
data && console.log(data.toString());
})
https://blog.csdn.net/qq_30113287/article/details/108052552
const http = require('http');
const url = require('url');
http.createServer(function(req, res){
res.writeHeader(200, {'Content-Type':'text/javascript;charset=UTF-8'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
res.write("网站名:" + params.name);
res.write("\n");
res.write("网站 URL:" + params.url);
res.end();
}).listen(3000);
扩展链接:https://www.cnblogs.com/zzsdream/p/11396076.html
express为第三方模块,需要下载
下载express —— npm install --save express
const express = require('express');
const app = express(); // 初始化一个express对象
app.listen(3000, () => { console.log('服务开启') }); // 开启一个服务器
//app.listen(端口号, 服务成功回调)
进行node调试使用,建议全局安装
npm install -g nodemon
nodemon 文件地址
,就是将node改为nodemon,其他相同静态资源托管
const static = express.static('文件夹路径');
app.use([path, ]static); // 使用今天资源
app.use('/public', express.static('public')); // 可以多次重复使用
// http://localhost:3000/public/index.html
app.get('/user/login/:id', (req, res) => { // 创建一个/user/login接口, 并进行监听
console.log('动态路由', req.params)
console.log('get请求', req.query); // req.query获取入参参数
// 然后进行逻辑操作
res.send('注册ok'); // 返回出参,可以是对象{err: 0, message: 'success'}
});
使用request
第三方模块:https://github.com/request/request
request.get('http://localhost:3000/user/login?a=10', function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body, '打印返回数据');
}
})
url内置模块
const urlData = new URL(urlString);
urlData.toString()
或toJSON()
querystring模块
用来处理url请求数据,不是返回数据
qs.stringify(dataObj, [分隔符], [键值对连接符])
qs.parse(dataString, [分割符], [键值连接符])
qs.escape(dataString)
qs.unescape(dataString)
const express = require('express');
const app = express(); // 初始化一个express对象
//用于解析x-www-form-urlencoded, 然后就可以读取req.body
app.use(express.urlencoded({ extended: false })); // 入参还有空对象是为true
//用于解析raw/json, 然后就可以读取req.body
app.use(express.json()); // 入参还有空对象是为true
app.post('/user/reg', (req, res) => {
console.log(req.body); // 此时可以直接打印
res.send('返回');
});
app.listen(3000);
request.post(
'http://localhost:3000/user/reg',
{
timeout: 1000,
json: true,
headers: { "content-type": "application/json" },
body: { key: 'value' } // 请求发送的数据
},
function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body, '打印返回数据');
}
}
)
request.post(
'http://localhost:3000/user/reg',
{ form: { key: 'value' } },
function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body, '打印返回数据');
}
}
)
或者叫做接口路由分配
如/user/reg
接口api,可以分成两级,所以可以进行分割,避免service文件冗余
// user.js文件,路由文件
// 新建router文件夹,建立user.js文件
const express = require('express');
const router = express.Router(); // 创建router对象。
// 编辑user下一级的接口api
router.get('/add', (req, res) => {
console.log(req.query);
res.send({ type: 'add' });
})
router.post('/updata', (req, res) => {
console.log(req.body); // 如果入口service已经完成post数据解析,就不需要再次进行
res.send({ type: 'updata' });
})
module.exports = router; // 导出router
const express = require('express');
const userRouter = require('./router/user'); // 引入user下的router
const app = express(); // 初始化一个express对象
const bpp = express(); // 再创建一个bpp,不建议创建一个express对象承载路由
// 处理post请求数据
app.use(express.urlencoded({ extended: false })); // 入参还有空对象是为true
app.use(express.json());
bpp.get('/login', (req, res) => {
console.log(req.body); // 此时可以直接打印
res.send('返回');
})
app.use('/use', userRouter); // 使用userRouter
app.use('/home', bpp); // 使用bpp, 这样就可以使用/home/login访问接口
app.use(['/one', '/tow'], bpp); // 同理
app.listen(3000);
其他请求和发送可以类推或者查看文档
res的方法:
res.send(返回值)
:常用的返回,可以返回对象,字符串,数组,buffer对象,模板页面res.json(返回值)
:可以返回对象,数组,json数据res.jsonp(返回值)
:jsonp的返回res.status(状态值)
:设置接口返回的状态值res.end()
:结束接口返回res.status(404).end()
res.render('ejs或者html地址')
res.type('octets/stream')
:设置content-type,返回数据类型const createError = require('http-errors')
// 放在所以接口的最下面,找不到接口是返回404
app.use(function (err, res, next) {
next(createError(404))
})
let { status, message } = createError(400, "服务器不理解请求的语法");
//此时status就是错误状态,message就是生成的错误提示
中间件就是接口接收前拦截器。
// 自定义全局中间件
app.use('/', (req, res, next) => {
console.log('中间件拦截');
// 可以进行token验证等身份信息确认拦截,判断是否执行next()
const { token } = req.headers;
if (token) next(); // 是否继续往下执行,有就执行,没有就不执行
else res.send({ code: 400, message: 'token is undefined' });
});
// 进行token拦截
// 如果第一个参数是'/', 则可以省略,原来是函数重载
// 所以body-parser, api路由载体router, 都是中间件
// 自定义局部中间件
// 中间件个数可为多个 app.get('pathName', fun, fun, fun...);
router.get('/add', (req, res, next) => {
// 为局部中间件
const { user } = req.query;
if (user === '123' ) next();
else res.send({ code: 400, message: 'user is wrong' });
}, (req, res) => {
console.log(req.query);
res.send({ type: 'add' });
})
如上面介绍的使用静态资源
app.all("*",function(req,res,next){
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin","http://localhost:8081");
//允许的header类型
res.header("Access-Control-Allow-Headers","content-type");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
if (req.method.toLowerCase() == 'options')
res.send(200); //让options尝试请求快速结束
else
next();
});
// 也可也上面的回调函数单独定义,使用app.use('/', callback)实现
文件下载
res.get('/use/download', (req, res) => {
const reqBody = req.body;
res.download('下载资源地址'[, '下载文件重命名'][, 报错回调函数])
})
// get和post的res都有download方法,直接使用就可以
文件流下载
req.get('/use/download', (req, res) => {
res.set({
// 告诉浏览器这是一个二进制文件
"Content-Type":"application/octet-stream",
// 告诉浏览器这是一个需要下载的文件
"Content-Disposition":"attachment; filename=1.xls"
});
res.send(二进制流);
// 二进制流获取
// 使用这个api获取文件流 fs.readFile默认读取文件二进制流
// 或者生成xls文件流
})
文件上传
文件上传使用multer
第三方模块:
文档链接:https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md
设置文件存储路径已经文件名称
const multer = require('multer'); // 引入multrer
// 使用硬盘存储模式设置存放接收到的文件的路径以及文件名
var storage = multer.diskStorage({
destination:function (req, file, cb) {
// 设置文件存储路径
// 接收到文件后输出的保存路径(若不存在则需要创建)
cb(null,'upload/');
},
filename:function (req, file, cb) {
// 设置文件存储名称
// 将保存文件名设置为 时间戳 + 文件原始名,比如 151342376785-123.jpg
cb(null, Date.now() +"-" + file.originalname);
}
});
检测存储路径是否被创建
var createFolder =function(folder){
try{
// 测试 path 指定的文件或目录的用户权限,我们用来检测文件是否存在
// 如果文件路径不存在将会抛出错误"no such file or directory"
fs.accessSync(folder);
}catch(e){
// 文件夹不存在,以同步的方式创建文件目录。
fs.mkdirSync(folder);
}
};
创建multer对象
// 创建 multer 对象
var upload = multer({ storage: storage });
/* POST upload listing. */
app.post('/upload', upload.single('file'), function(req, res, next) {
var file = req.file;
console.log('文件类型:%s', file.mimetype);
console.log('原始文件名:%s', file.originalname);
console.log('文件大小:%s', file.size);
console.log('文件保存路径:%s', file.path);
// 接收文件成功后返回数据给前端
res.json({res_code:'0'});
});
测试
<form action="http://localhost:3000/upload" method="post" enctype="multipart/form-data">
<input type="file" name="logo" />
<input type="submit" value="提交">
form>
使用插件apidoc
自动生成接口文档
参考1:https://blog.csdn.net/qq_32352777/article/details/102746237
全局下载:cnpm install -g apidoc
根据参考1:在项目根目录创建并写入apidoc.json
在需要的接口上面写入注释
常用的注释模板
/**
* @api { 请求类型 } 接口地址 接口名称
* @apiGroup 接口分类名称
* @apiVersion 接口版本号
* @apiDescription 接口描述
* @apiName 接口名
* @apiParam (入参传入位置) { 入参数据类型 } 入参参数名称 入参描述
* @apiParam (params) { String } petId 请求参数2
*
* @apiSuccess { 出参数据类型 } 出参参数名称 出参描述
* @apiSuccess { String } msg 接口返回信息
* @apiSuccessExample { json } 出参参考模板名称:
* {
* "code" : "0",
* "msg" : "注册成功"
* }
* @apiSuccessExample { json } Error-Response:
* {
* "code" : "-1",
* "msg" : "注册失败"
* }
*/
生成模板
可以命令行操作,也可以在package.json里面配置
"scripts": {
"docs": "apidoc -i ./src/routes -o ./public/docs"
},
代理
转接请求,使用http-proxy-middleware
第三方模块
文档:https://www.npmjs.com/package/http-proxy-middleware
const proxy = require('http-proxy-middleware')
app.use('/api', proxy({
target: "http://www.baidu.com", // 目标主机
changeOrigin: true, // 虚拟托管站点需要
ws : true , // 代理 websockets
pathRewrite: { // 重写路径, 如下, 转接请求是
"^/api": "/"
},
router : {
// 当request.headers.host == 'dev.localhost:3000',
// 将目标 http://www.baidu.com' 覆盖为 'http://localhost:8000'
'dev.localhost:3000' : 'http://localhost:8000' ,
},
}))
第三方模块查找访问网站:www.npmjs.com
使用第三方插件:cross-env
使用:在package.json
文件内使用
"scripts": {
"dev": "cross-env abc='development' node ./src/main.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
然后就可以在代码里面打印变量了,通常设置NODE_ENV
,这里设置abc
为了演示
console.log(process.env.abc)
邮箱验证码 —— Nodemailer
const nodemailer = require("nodemailer"); // 创建发送的请求对象
let transporter = nodemailer.createTransport({
// 在node_modal\\nodemailer\\lib\\well-know-services.json查找对应邮箱的host
host: "smtp.qq.com", // 发送方邮箱
port: 465, // 端口号
secure: true, // true for 465, false for other ports
auth: {
user: '[email protected]', // 发送方的邮箱地址
pass: 'qrdccraawqnifjgj', // smtp 验证码
},
});
// 邮件信息编写
const mailobj = {
from: '"Fred Foo " <[email protected]>', // '"发送方名称" <邮箱号>'
to: "[email protected]",
// 群发字符串用逗号拼接--"[email protected], [email protected]"
subject: "验证标题", // 邮件标题
// 注意:text和html只能存一个, html权限大于text
// text: "你的验证码是123456", // 邮箱文字内容 只能字符串格式
html: `
Hello world?
`, // html body
attachments: [
{
filename : 'content', // 附件名称
content : '发送内容' // 附件文字内容
},
{
filename: 'packjson', // 附件名称
path: './package.json', // 附件本地地址
},
{
filename: "test.JPG",
path: "./src/assets/images/timg.jpg",
cid: "01", // 邮箱正文插入图片
}
]
};
// 发送邮件,不要循环发送,会封
transporter.sendMail(
mailobj,
(err, data) => {
err && console.log(err); // 发送失败后报错
data && console.log(data); // 发送成功后返回信息
}
);
api:https://nodemailer.com/about/
短信验证码 —— 没钱买服务
使用jwt-simple
第三方模块生成token
const jwt = require('jwt-simple')
const str = '12345678' // 秘钥
const res = { name: 'admin', lastTime: '15:39' } // 需要存储的信息
// 进行加密
const token = jwt.encode(res, str)
console.log(token, '--------加密')
// 进行解密
const word = jwt.decode(token, str)
console.log(word, '---------解密')
// 然后通过时间判断是否token过期
使用第三方插件:nodejs-websocket
教程:https://www.cnblogs.com/yangsg/p/10675533.html
进阶:图片或文件传递
conn.on("binary", function (inStream) {
var data = Buffer.alloc(0)
// 处理二进制数据
inStream.on("readable", function () {
var newData = inStream.read()
if (newData) data = Buffer.concat([data, newData], data.length+newData.length)
})
// 返回二进制数据
inStream.on("end", function () {
console.log("Received " + data.length + " bytes of binary data")
console.log('发生数据给game2')
game2.sendText('接受数据')
game2.sendBinary(data)
})
})
game1:修改部分
ws.onmessage = function (e) {
mess.innerHTML = "连接成功"
document.querySelector(".kuang").onclick = function (e) {
var time = new Date();
ws.send(time + " game1点击了“" + e.target.innerHTML + "”");
}
var inputElement = document.getElementById("file");
inputElement.onchange = function (e) {
var file = (e.target.files)[0]
ws.send(file);
}
}
game2: 修改部分
ws.onmessage = function (e) {
if (typeof (e.data) === 'string') {
var time = new Date();
mess.innerHTML += time + "的消息:" + e.data + "
"
} else {
var reader = new FileReader();
reader.onload = function (evt) {
if (evt.target.readyState == FileReader.DONE) {
var url = evt.target.result;
alert(url);
var img = document.getElementById("imgDiv");
img.innerHTML = "+url+" />";
}
}
reader.readAsDataURL(e.data);
}
}
此时就完成了图片等等文件的传递
开发第三分模块并上传npm
npm init
创建环境npm login
,根据提示登录npmnpm adduser
,在注册表注册npm账户信息npm publish
,将自己的项目提交到npmconst md5 = require('md5');
const str = '123456'
console.log(md5(str)) // 获取到加密后数据
/**
* json,二维数组相互转换
*
* @param { Array } data // 需要转换的数据
* @param { Array } getArr // 需要提取的值,会按照数组顺序提取
* @param { String } type // 为json时:jsonToArray,为array时:arrayToJson。
*
* @return { Array } // 返回二维数组
*
* 示例:
* const getArr = jsonSwitchArr(json, ["user", "password"], 'json')
* const getJson = jsonSwitchArr(arr, ["user", "password"], 'array')
*/
function jsonSwitchArr (data, getArr, type) {
const res = []
if (Object.prototype.toString.call(data) !== "[object Array]") return res
if (Object.prototype.toString.call(getArr) !== "[object Array]") return res
if (type === 'json') {
data.forEach(item => {
let child = []
getArr.forEach(key => { child.push(item[key] || '') })
res.push(child)
})
}
if (type === 'array') {
data.forEach(item => {
let obj = {}
getArr.forEach(key => { obj[key] = item || '' })
res.push(obj)
})
}
return res
}
官网:https://www.mongodb.com/download-center/enterprise
安装时不要勾选install mongodb compass
,点击后下载官方可视化管理工具,安装不上。
安装教程:https://www.cnblogs.com/zhif97/p/12806245.html
mongo
进入环境,开始进行增删改成操作show dbs
:显示所有的数据库db
:显示当前正在使用的数据库use 数据库名
:切换到指定的数据库,有就切换,没有就创建切换db.dropDatabase()
:删除当前执行的数据库db.createCollection("集合名",{capped:true,size:1024\*30})
:创建一个集合
capped:true.指定库的大小,默认false,即自动分配
size:1024*30这是30m的库,基于kb的
show collections : 查看当前使用集合
了解就行,不需要记,基本是多余的一步
db.集合名.insertOne(写入集合的一条数据)
:像集合写入一条数据,没有此集合会先创建再写入db.集合名.insertMany(数组对象)
:写入多条数据,同上show collections
:查看当前库里面所有的集合use 集合名
:切换到指定的集合db.集合名.drop()
:删除指定的集合,但必须是切换到集合所在库的环境下进行。db.集合名.remove({})
:清空集合内的所有数据注意:由于写入的是键值对,所有查找的条件也必须是{键值对}。
db.集合名.find()
:查看集合全部数据db.集合名.find(条件)
:按条件进行精确查找db.集合名.find(条件1,条件2)
查找满足条件1且满足条件2db.集合名.find($or:[条件1,条件2])
查找满足条件1或者条件2db.集合名.findOne(条件)
:查找显示符合条件的第一条数据db.集合名.find({"键":{$regex:"值"}})
:按条件模糊查询db.集合名.find({"键":正则表达式})
使用正则条件查询db.集合名.find({"age":{$gt:20}})
:查找年龄大于20$gt
:大于$lt
:小于$gte
:大于等于$lte
:小于等于$ne
:不等于$eq
:等于db.集合名.find().sort({age:1})
:按照年龄的正序查找db.集合名.find().sort({age:-1})
:按照年龄的倒序查找db.集合名.find().count()
:获取集合有条数db.集合名.find().skip(数字)
:获取指定条后的数据db.集合名.find().limit(数字)
:指定获取多少条数据db.集合名.find().skip(数字).limit(数字)
:获取指定条后的几条数据db.集合名.find({field: {$in: [ '值1', '值2' ]}})
; field只要和array中的任意一个value相同,那么该文档就会被检索出来 —— 包含$nin
—— 不包含db.集合名.remove(条件)
:删除指定条件的数据
db.集合名.deleteMany({})
:删除所有数据
db.集合名.deleteMany({条件对象})
:删除所有符合条件的数据
其他的和查找数据一样,
db.集合名.update(筛选条件,{重新写入内容},false)
:重新写入筛选出来的数据。默认false,即筛选不到不创建。改成true就会创建db.集合名.update(筛选条件,($set{重新部分内容}))
:修改部分内容。同上为集合建立索引,基于title(还可以是id,就是建立主键)作用是加快查询
>db.col.createIndex({"title":1})
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。
> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "runoob.com",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
>
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { s u m : " sum : " sum:"likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { a v g : " avg : " avg:"likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m i n : " min : " min:"likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m a x : " max : " max:"likes"}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { p u s h : " push: " push:"url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { a d d T o S e t : " addToSet : " addToSet:"url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : { f i r s t : " first : " first:"url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : { l a s t : " last : " last:"url"}}}]) |
教学网站:https://blog.csdn.net/weixin_39999535/article/details/81383196
上面的软件是付费使用的,还有免费的软件NoSQLBooster
软件的使用基本一样,链接数据库需要百度看看
上面的增删改查(CURD)操作的mongodb语法上面有
使用插件Mongoose:http://www.mongoosejs.net/docs/guide.html
const mongoose = require('mongoose'); // 引入mongoose
// 通过将useNewUrlParser设置为true来避免“不建议使用当前URL字符串解析器”警告
mongoose.connect('mongodb://localhost/runoob', { useNewUrlParser: true, useUnifiedTopology: true }); // 链接数据库
const db = mongoose.connection; // 数据库链接对象
db.on('error', console.error.bind(console, 'connection error')); // 数据库链接失败钩子
db.once('open', () => { // 数据库链接成功钩子
console.log('数据库链接成功');
})
mongodb每个数据库里面有多个集合(表),需要先拟定一个表结构。schema就是表结构对象
值得注意的是:此时定义的表结构和数据库还没有关联在一起
const Schema = mongoose.Schema;
const userSchema = new Schema({
use: { type: String, required: true }, // 表头use, 类型字符串,必填项
password: { type: String, required: true }, // 表头password
age: Number, // 表头age, 类型Number, 非必填
sex: { type: Number, default: 0 }, // 性别,数字类型,默认为无性别
date: { type: Date, default: new Date() } // 时间,时间类型,默认当前时间
})
就是把定义的表结构Schema和集合关联在一起
// 将定义的表结构和集合名进行链接 (集合名,定义的表结构对象)
// 有集合则会根据定义的表结构写入数据,不会改变原有表结构数据
// 没有集合则创建新集合
const User = mongoose.model('user', userSchema);
// 数据插入操作,入参为json数据
User.insertMany([{ use: '张旭', password: '123', age: 12 }])
.then(data => { console.log(data, "数据插入成功") })
.catch(err => console.log(err))
// 数据查询操作
User.find(条件) // 和mongodb的选择语法一样
.then(data => console.log(data, '数据查询成功'))
.catch(err => console.log(err))
// 数据分页查询操作
// 就是通过链式调用完成 skip为跳过几条数据,limit为返回几条数据
User.find().skip(1).limit(2)
.then(data => console.log(data, '数据查询成功'))
.catch(err => console.log(err))
// 数据模糊查询操作 --- 同上原理,再find参数里加mongodb模糊语法
// 指定条数返回查询 --- 同上原理,仅调用limit即可
// 获取全部总条数
User.count()
.then(total => console.log(total, total/10, '查询全部数据总数'))
.catch(err => console.log(err));
// 数据修改操作 --- 尽量通过id进行修改 或 多条件匹配修改
User.updateMany({ use: '憨憨' }, { use: '笨笨'})
.then(data => { console.log(data, '数据修改成功') })
.catch(err => console.log(err));
// 数据删除操作
User.remove() // 和mongodb的选择语法一样
.then(data => console.log(data, '数据删除成功'))
.catch(err => console.log(err))
// 数据批量删除
User.deleteMany() // 和mongodb的语法一样
.then(data => console.log(data, '数据批量删除成功'))
.catch(err => console.log(err))
xls
数据导入到数据库
node-xlsx
转换为二维数组node-xlsx
转换为xls
二进制文件流npm install express-generator -g
express app