需求:图书的增删改查,图书数据保存在data.json文件中。

1、Demo结构:

  

2、首先下载安装node.js,配置环境变量:参考博客

3、项目初始化

  1)创建项目根目录node-hello,进入到根目录node-hello,右键/在此处打开PowerShell窗口。

  2)创建app.js文件。

  3)在控制台输入命令:npm init -y,会自动创建package.json文件。

  4)在控制台输入命令:npm install mime,会自动创建node_modules文件夹,并下载mime模块到该文件夹,还会自动生成package-lock.json文件。

  5)npm install underscore,下载underscore模块。underscore的使用参考博客

4、入口文件app.js

// 加载http模块
var http = require("http");
var fs = require("fs");
var path = require("path");
var mime = require("mime");
var url = require("url");
var querystring = require("querystring");
var _ = require("underscore"); // 创建一个http服务对象
http.createServer(function(req, res) { req.url = req.url.toLowerCase();
req.method = req.method.toLowerCase();
if (req.method === 'get') {
// 通过url模块的parse方法获取用户get请求提交的数据
// 第二个参数为true时,urlObj的query属性就是所有的请求参数,类型是json对象
var urlObj = url.parse(req.url, true);
// console.log(urlObj);
} // 封装fender函数,将render函数挂在到res对象上;第二个参数是模板数据
res.render = function (filename, templateData) {
fs.readFile(filename, function(err, data) {
if(err) {
res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
res.end("404, not found.");
return;
} if (templateData) {
var fn = _.template(data.toString("utf-8"));
data = fn(templateData);
} res.setHeader('Content-Type', mime.getType(filename));
res.end(data);
});
}; if(req.url === '/' || req.url === '/index') {
res.render(path.join(__dirname, 'pages/index.html'));
}
else if(req.url === '/list') {
// 第一步:读取data.json文件中的数据,转换为list数组
fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var bookList = JSON.parse(data || '[]'); // json数组 // 第二步:在服务器使用模版引擎,将bookList数据和list.html页面结合
res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
});
}
else if(req.url.startsWith('/add')) {
res.render(path.join(__dirname, 'pages/add.html'));
}
else if(req.url.startsWith('/submit') && req.method === 'get') { // 如何获取get请求的参数
// 用户表单提交get请求数据,保存到data/data.json文件中,新数据以追加的形式添加
console.log(req.url); // /summit?name=xxx&price=xxx // 首先读取data.json文件的内容
fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var list = JSON.parse(data || '[]'); // json数组 // 获取get请求的参数,将用户提交的数据添加到json数组
var book = urlObj.query;
// book.id = list.length + 1;
book.id = list[list.length - 1].id + 1;
list.push(book);
console.log("添加一条记录后,data.json的内容:" + JSON.stringify(list)); // 将json数组写入data.json文件
fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
if(err) throw err;
console.log('写入成功');
});
}); // 重定向
res.statusCode = 302;
res.statusMessage = 'Found';
res.setHeader('Location', '/index');
res.end();
}
else if(req.url.startsWith('/submit') && req.method === 'post') { // 如何获取post请求的参数
var array = []; // 用来保存用户post请求提交的数据
var postBody;
req.on('data', function(chunk) {
// chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
console.log("data事件...");
array.push(chunk);
}); req.on('end', function() {
console.log("end事件...");
// 把array中多个Buffer对象汇总到一个Buffer对象
postBody = Buffer.concat(array);
console.log("postBody: " + postBody); // postBody: name=1&price=1
}); fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var list = JSON.parse(data || '[]'); // json数组 // 获取get请求的参数,将用户提交的数据添加到json数组
// querystring对象可以把表单数据 name=xxx&price=xxx => {"name":"xxx","price":"xxx"}
var book = querystring.parse(postBody.toString("utf-8"));
// book.id = list.length + 1;
book.id = list[list.length - 1].id + 1;
list.push(book);
console.log("添加一条记录后,data.json的内容:" + JSON.stringify(list)); // 将json数组写入data.json文件
fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
if(err) throw err;
console.log('写入成功');
});
}); /*
// 首先读取data.json文件的内容
fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var list = JSON.parse(data || '[]'); // json数组 // 获取post请求的参数,将用户提交的数据添加到json数组
// 因为post提交数据的时候,数据量可能比较大,所以可能分多次提交,每次添加一部分数据
// 此时服务器要获取用户提交的所有数据,必须监听request对象的data事件
// 什么时候表示浏览器把所有数据都提交到服务器了呢?当request对象的end事件触发
var array = []; // 用来保存用户post请求提交的数据
console.log("111...");
req.on('data', function(chunk) {
// chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
console.log("data事件...");
array.push(chunk);
});
req.on('end', function() {
console.log("end事件...");
// 把array中多个Buffer对象汇总到一个Buffer对象
var postBody = Buffer.concat(array);
console.log("postBody: " + postBody);
list.push(postBody);
console.log("添加一条记录后,data.json的内容:" + JSON.stringify(list)); // 将json数组写入data.json文件
fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
if(err) throw err;
console.log('写入成功');
});
}); console.log("222...");
});*/ // 重定向
res.statusCode = 302;
res.statusMessage = 'Found';
res.setHeader('Location', '/index');
res.end();
}
else if(req.url.startsWith('/detail') && req.method === 'get') {
var queryId = urlObj.query.id; // 第一步:读取data.json文件中的数据,转换为list数组
fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var bookList = JSON.parse(data || '[]'); // json数组 // 查询指定id的记录
var book = {};
for (var i = 0; i < bookList.length; i++) {
if (bookList[i].id == queryId) { // 不能写“===”,因为queryId是字符串类型
book = bookList[i];
}
} // 第二步:在服务器使用模版引擎,将数据和detail.html页面结合
res.render(path.join(__dirname, 'pages/detail.html'), {book:book});
});
}
else if(req.url.startsWith('/delete') && req.method === 'get') {
var queryId = urlObj.query.id; // 第一步:读取data.json文件中的数据,转换为list数组
fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var bookList = JSON.parse(data || '[]'); // json数组 // 删除指定id的记录
for (var i = 0; i < bookList.length; i++) {
if (bookList[i].id == queryId) {
bookList.splice(i, 1); // 删除起始下标为queryId-1,长度为1的元素
}
} // 将json数组重新写入data.json文件
fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(bookList), function(err) {
if(err) throw err;
console.log('写入成功');
}); // 第二步:在服务器使用模版引擎,将bookList数据和list.html页面结合
res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
});
}
else if(req.url.includes('static')){
res.render(path.join(__dirname, req.url));
}
else if(req.url.startsWith('/edit') && req.method === 'post') {
var array = []; // 用来保存用户post请求提交的数据
var postBody;
req.on('data', function(chunk) {
// chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
console.log("data事件...");
array.push(chunk);
}); req.on('end', function() {
console.log("end事件...");
// 把array中多个Buffer对象汇总到一个Buffer对象
postBody = Buffer.concat(array);
}); fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;} var bookList = JSON.parse(data || '[]'); // json数组 // 获取get请求的参数,将用户提交的数据添加到json数组
// querystring对象可以把表单数据 name=xxx&price=xxx => {"name":"xxx","price":"xxx"}
var book = querystring.parse(postBody.toString("utf-8"));
console.log("=============book:" + book.id + book.name + book.price);
for (var i = 0; i < bookList.length; i++) {
// console.log("bookList[i].id=" + bookList[i].id);
// console.log("book.id=" + book.id);
// console.log(bookList[i].id == book.id);
if(bookList[i].id == book.id) {
bookList[i].name = book.name;
bookList[i].price = book.price;
}
} // 将json数组重新写入data.json文件
fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(bookList), function(err) {
if(err) throw err;
console.log('写入成功');
}); // 重定向
res.statusCode = 302;
res.statusMessage = 'Found';
res.setHeader('Location', '/list');
res.end();
});
}
else {
res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
res.end("404,not found!");
}
}).listen('8080', function() {
console.log('服务器已经启动,请访问http://127.0.0.1:8080/');
});

5、common.css

h2 {
background-color: #ccc;
}

6、html页面

  add.html

<!DOCTYPE html>
<html>
<head>
<title>add页面</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/static/css/common.css">
</head>
<body>
<h2>add页面</h2>
<form method="get" action="/submit">
<!-- <form method="post" action="/submit"> -->
书名: <input type="text" name="name">
价格: <input type="text" name="price">
<input type="submit" value="添加">
</form>
</body>
</html>

  detail.html

<!DOCTYPE html>
<html>
<head>
<title>detail页面</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/static/css/common.css">
</head>
<body>
<h2>detail页面</h2>
<form method="post" action="/edit">
<input type="hidden" name="id" value="<%= book.id %>">
书名:<input type="text" name="name" value="<%= book.name %>"><br/>
价格:<input type="text" name="price" value="<%= book.price %>"><br/>
<input type="submit" value="修改">
</form>
</body>
</html>

  index.html

<!DOCTYPE html>
<html>
<head>
<title>index页面</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/static/css/common.css">
</head>
<body>
<h2>index页面</h2>
<!-- <img src="/static/images/1.jpg">
<img src="/static/images/2.png"> -->
<a href="/list">图书列表</a>
</body>
</html>

  list.html

<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<title>list页面</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/static/css/common.css">
</head>
<body>
<h2>list页面</h2>
<%= msg %>!</h2><br/>
<!-- <img src="/static/images/1.jpg">
<img src="/static/images/2.png"> -->
<a href="/add">添加</a> <table border="1" cellpadding="0">
<tr>
<td>ID</td>
<td>书名</td>
<td>价格</td>
<td>操作</td>
</tr>
<% for(var i = 0; i < bookList.length; i++) { %>
<tr>
<td><%= bookList[i].id %></td>
<td><%= bookList[i].name %></td>
<td><%= bookList[i].price %></td>
<td>
<a href="/detail?id=<%= bookList[i].id %>">查看</a>
<a href="/delete?id=<%= bookList[i].id %>">删除</a>
</td>
</tr>
<% } %>
</table> </body>
</html>

7、node app.js启动项目,浏览器访问主页 :http://127.0.0.1:8080/

  

  

  

  测试完后data.json文件的数据:

[{"id":1,"name":"射雕英雄传","price":"45.00"},{"id":2,"name":"天龙八部2","price":"66.00"},
{"id":3,"name":"倚天屠龙记","price":"50.00"},{"id":4,"name":"Java编程思想2","price":"40.00"},
{"name":"Java从入门到精通","price":"30.00","id":6},{"name":"ggf","price":"fff","id":8},
{"name":"af","price":"ff","id":9}]

 

8、封装app.js里面重复代码

// 加载http模块
var http = require("http");
var fs = require("fs");
var path = require("path");
var mime = require("mime");
var url = require("url");
var querystring = require("querystring");
var _ = require("underscore"); // 创建一个http服务对象
http.createServer(function(req, res) { req.url = req.url.toLowerCase();
req.method = req.method.toLowerCase();
if (req.method === 'get') {
// 通过url模块的parse方法获取用户get请求提交的数据
// 第二个参数为true时,urlObj的query属性就是所有的请求参数,类型是json对象
var urlObj = url.parse(req.url, true);
// console.log(urlObj);
} // 封装fender函数,将render函数挂在到res对象上;第二个参数是模板数据
res.render = function (filename, templateData) {
fs.readFile(filename, function(err, data) {
if(err) {
res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
res.end("404, not found.");
return;
} if (templateData) {
var fn = _.template(data.toString("utf-8"));
data = fn(templateData);
} res.setHeader('Content-Type', mime.getType(filename));
res.end(data);
});
}; if(req.url === '/' || req.url === '/index') {
res.render(path.join(__dirname, 'pages/index.html'));
}
else if(req.url === '/list') {
// 第一步:读取data.json文件中的数据,转换为list数组
readFile(function(bookList) {
// 第二步:使用模版引擎,将bookList数据和list.html页面结合
res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
});
}
else if(req.url.startsWith('/add')) {
res.render(path.join(__dirname, 'pages/add.html'));
}
else if(req.url.startsWith('/submit') && req.method === 'get') { // 如何获取get请求的参数
// 用户表单提交get请求数据,保存到data/data.json文件中,新数据以追加的形式添加
console.log(req.url); // /summit?name=xxx&price=xxx // 第一步:读取data.json文件中的数据,转换为list数组
readFile(function(list) {
// 第二步:获取get请求的参数,将用户提交的数据添加到json数组
var book = urlObj.query;
book.id = list[list.length - 1].id + 1;
list.push(book);
console.log("添加一条记录后,data.json的内容:" + JSON.stringify(list)); // 第三步:将json数组写入data.json文件,并重定向到list页面
writeFile(list, res);
});
}
else if(req.url.startsWith('/submit') && req.method === 'post') { // 如何获取post请求的参数
// 用户表单提交post请求数据,保存到data/data.json文件中,新数据以追加的形式添加
getPostBodyData(req, function(book) { // post请求数据封装成book(json对象)
// 读取data.json文件中的数据,转换为list数组
readFile(function(list) {
book.id = list[list.length - 1].id + 1;
list.push(book);
// console.log("添加一条记录后,data.json的内容:" + JSON.stringify(list)); // 将json数组写入data.json文件,并重定向到list页面
writeFile(list, res);
});
});
}
else if(req.url.startsWith('/detail') && req.method === 'get') {
// 第一步:读取data.json文件中的数据,转换为list数组
readFile(function(bookList) {
// 第二步:查询指定id的记录
var book = {};
for (var i = 0; i < bookList.length; i++) {
// 不能写"===",因为urlObj.query.id是字符串类型
if (bookList[i].id == urlObj.query.id) {
book = bookList[i];
break;
}
} // 第三步:使用模版引擎,将数据和detail.html页面结合
res.render(path.join(__dirname, 'pages/detail.html'), {book:book});
});
}
else if(req.url.startsWith('/delete') && req.method === 'get') {
// 第一步:读取data.json文件中的数据,转换为list数组
readFile(function(bookList) {
// 第二步:删除指定id的记录
for (var i = 0; i < bookList.length; i++) {
if (bookList[i].id == urlObj.query.id) {
bookList.splice(i, 1); // 删除起始下标为queryId-1,长度为1的元素
break;
}
} // 第三步:将json数组重新写入data.json文件,并重定向到list页面
writeFile(bookList, res);
});
}
else if(req.url.includes('static')){
res.render(path.join(__dirname, req.url));
}
else if(req.url.startsWith('/edit') && req.method === 'post') {
getPostBodyData(req, function(book) { // post请求数据封装成book(json对象)
console.log("=============book:" + book.id + book.name + book.price);
// 读取data.json文件中的数据,转换为list数组
readFile(function(bookList) {
for (var i = 0; i < bookList.length; i++) {
// console.log("bookList[i].id=" + bookList[i].id);
// console.log("book.id=" + book.id);
console.log(bookList[i].id == book.id);
if(bookList[i].id == book.id) {
bookList[i].name = book.name;
bookList[i].price = book.price;
break;
}
} // 将json数组重新写入data.json文件,并重定向到list页面
writeFile(bookList, res);
});
});
}
else {
res.writeHead(404, 'not found', {'Content-Type': 'text/html; charset=utf-8'});
res.end("404,not found!");
}
}).listen('8080', function() {
console.log('服务器已经启动,请访问http://127.0.0.1:8080/');
}); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 封装读取data.json文件的方法
function readFile(callback) {
fs.readFile(path.join(__dirname, 'data', 'data.json'), 'utf-8', function (err, data) {
if(err && err.code !== 'ENOENT') {throw err;}
console.log("data.json原来的内容:" + data); // [{"name":"xxx","price":"xxx"}]]
var bookList = JSON.parse(data || '[]'); // json数组
callback(bookList);
});
} // 封装写入data.json文件的方法
function writeFile(list, res) { // 参数list的类型:json数组
fs.writeFile(path.join(__dirname, 'data', 'data.json'), JSON.stringify(list), function(err) {
if(err) throw err;
console.log('写入成功'); // 重定向
res.statusCode = 302;
res.statusMessage = 'Found';
res.setHeader('Location', '/list');
res.end(); // 使用模版引擎,将bookList数据和list.html页面结合
// res.render(path.join(__dirname, 'pages/list.html'), {msg:'这是list页面', bookList:bookList});
});
} // 封装写入data.json文件的方法
function writeFile2(data, callback) { // 参数data的类型:字符串
fs.writeFile(path.join(__dirname, 'data', 'data.json'), data, function(err) {
if(err) throw err;
console.log('写入成功'); // 调用callback()来执行当写入数据完毕后的操作
callback();
});
} // 封装获取用户post提交的数据的方法
function getPostBodyData(req, callback) {
var array = []; // 用来保存用户post请求提交的数据
var postBody;
req.on('data', function(chunk) {
// chunk就是浏览器本次data事件提交的一部分数据;chunk是Buffer类型
console.log("data事件...");
array.push(chunk);
}); req.on('end', function() {
console.log("end事件...");
// 把array中多个Buffer对象汇总到一个Buffer对象
var postBody = Buffer.concat(array); // 此处postBody类型:Buffer
// console.log("postBody: " + postBody); // postBody: name=1&price=1
// querystring对象可以把表单数据 name=xxx&price=xxx => {"name":"xxx","price":"xxx"}
postBody = querystring.parse(postBody.toString("utf-8")); // 此处postBody类型:json对象
callback(postBody);
});
}

node.js入门学习(四)--Demo图书的增删改查的更多相关文章

  1. Django基础学习四_数据库的增删改查

    今天主要学习两个东西 1.如何对数据库做增删改查 2.如果将数据库中的数据用html的方式返回到前台 一.对数据库中增删改查操作 1.首先需要先见表,见表的方法我们在“http://www.cnblo ...

  2. node.js 实现接口-操作文件进行用户增删改查

    首先安装npm,使用npm安装express npm install express -S /* * @Author: yinxin * @Date: 2020-03-27 10:18:41 * @L ...

  3. Node+Express+node-mysql 实战于演习 全套mysql(增删改查)

    最近这段时间研究Node感觉不错,自己做了一个增删改查,虽然有些简陋,但是思想是想通的,其实所有项目都是增删改查,有助于初学者快速掌握Node 首先 本实例展示的是基于Node+Express+nod ...

  4. 基于renren-fast的快速入门项目实战(实现报表增删改查)

    基于renren-fast的快速入门项目实战(实现报表增删改查) 说明:renren-fast是一个开源的基于springboot的前后端分离手脚架,当前版本是3.0 官方开发文档需付费,对于新手而言 ...

  5. Mysql学习笔记(六)增删改查

    PS:数据库最基本的操作就是增删改查了... 学习内容: 数据库的增删改查 1.增...其实就是向数据库中插入数据.. 插入语句 insert into table_name values(" ...

  6. ssm学习(四)--完整的增删改查demo

    上一篇文章简要介绍了将sping mvc加入整个框架,算是完成了ssm的集成.本节继续前面的内容,结合spring mvc做一个简单的增删改查demo. 1.首先,重写一下GeckoList.jsp页 ...

  7. ES6学习笔记(三):教你用js面向对象思维来实现 tab栏增删改查功能

    前两篇文章主要介绍了类和对象.类的继承,如果想了解更多理论请查阅<ES6学习笔记(一):轻松搞懂面向对象编程.类和对象>.<ES6学习笔记(二):教你玩转类的继承和类的对象>, ...

  8. MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

    上篇文章中 我们已经创建了EF4.1基于code first的例子  有了数据库 并初始化了一些数据  今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建 ...

  9. MongoDB学习总结(二) —— 基本操作命令(增删改查)

    上一篇介绍了MongoDB在Windows平台下的安装,这一篇介绍一下MongoDB的一些基本操作命令. 下面我们直奔主题,用简单的实例依次介绍一下. > 查看所有数据库 (show dbs) ...

随机推荐

  1. 【神经网络与深度学习】【VS开发】【CUDA开发】VS2013 配置CUDNN V4 DEMO

    VS2013 配置CUDNN V4 DEMO 众所周知,当前主流深度学习的实现中调用的底层API都是cudnn,自己做项目需要开发深度学习模块时,也需要调用cudnn库,因此熟悉cudnn库是很有必要 ...

  2. docker mysql 容器报too many connections 引发的liunx磁盘扩容操作

    症状每次删除mysql容器重启没两分钟又报标题错 df -h 命令查看各个挂载空间应用情况发现root home var 三个文件目录挂载的空间满了 网上百度了一下liunx磁盘扩容操作,fdisk ...

  3. Angular5 自定义scrollbar样式之 ngx-malihu-scrollbar

    简介 此插件是 Malihu jQuery Scrollbar 为了在 Angular2+ 环境下使用,封装的一个ts的版本.提供directive和service. 从安装量来看,它比不过 perf ...

  4. spring boot-2.Hello world

    由于 个人习惯,我选择使用STS来作为开发工具.跳过手动构建spring boot 项目的环节,直接使用向导创建spring boot 项目. 1.创建spring boot项目 File ----& ...

  5. Linux环境下Oracle安装参数设置

    前面讲了虚拟机的设置和OracleLinux的安装,接下来我们来说下Oracle安装前的准备工作.1.系统信息查看系统信息查看首先服务器ip:192.168.8.120服务器系统:Oracle Lin ...

  6. 模板 - 强连通分量 - Kosaraju

    Kosaraju算法 O(n+m) vector<int> s; void dfs1(int u) { vis[u] = true; for (int v : g[u]) if (!vis ...

  7. 运维LVS三种模式十种调度算法

    一.LVS简介 LVS(Linux Virtual Server)即Linux虚拟服务器,是由章文嵩博士主导的开源负载均衡项目,目前LVS已经被集成到Linux内核模块中.该项目在Linux内核中实现 ...

  8. drf三大认证解析

    目录 三大认证 认证模块: 权限模块 频率模块 RABC author组件 认证权限六表. Content_type 认证与权限工作原理+自定义认证类 自定义权限类 admin关联自定义用户表 前后台 ...

  9. vue笔记(更新中)

    1.禁止div点击 2.禁止选择 -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; - ...

  10. ARM仿真器之驱动黄色惊叹号

    JLink CDC UART PORT 黄色惊叹号 Windows 无法验证此设备所需的驱动程序的数字签名.某软件或硬件最近有所更改,可能安装了签名错误或损毁的文件,或者安装的文件可能是来路不明的恶意 ...