Node进阶第五天

为什么mysql不用开mongod –dbpath xx…

答:因为mysql会在”服务”中运行,也就是开机时自动启动并且长久驻扎在内存中了。

mongodb其实也能通过设置来设成windows中的服务。

案例:

01每次GET /的时候插入一条数据。

(具体api可以查看mongodb的文档)

const MongoClient = require('mongodb').MongoClient;

var express = require('express');

var app = express();

app.listen(3000);

app.get("/", (req, res) => {

const url = 'mongodb://localhost:27017/';

const dbName = 'myproject';

MongoClient.connect(url,{useNewUrlParser:true}, function (err, client) {

//回调函数表示连接成功做的事情

if(err){

console.log("数据库连接失败");

return;

}

console.log("数据库连接成功");

const db = client.db(dbName);

//插入数据,集合如果不存在,也没有关系,程序会帮你创建

db.collection('student').insertOne({

"name":"哈哈",

"age": parseInt(Math.random() *100 + 10)

},function(err,result){

if(err){

console.log(err);

return;

}

//插入之后做的事情,result表示插入结果。

console.log(result);

res.send(result);

client.close();

});

});

});

02把常用的增删改查,都封装成为module

DAO data access object 数据访问对象

是一个数据访问接口。

使用我们自己写的模块来完成数据库的操作。

一、     数据库

想想我们的百度百家Ajax案例,当时调用了百度的JSON,有一个参数叫做page=3,生成的JSON,

这个就是分页,就是我们像寻找所有的新闻,但是是位于第三页的新闻。那么有两种做法:

1)     错误的做法:就是将所有的result都读取到数组,然后进行数据操作,进行分页;

2)     正确的做法:就是在数据库中,只读取这么多内容。

错误的,我们试图每次都读取全部数据,但是这样开销很大

db.find(“student”,{},function(err,result){

for(var i = 10*page;i<10*(page+1);i++)

{

a.push(result[i]);

}

res.send(a);

});

所以,mongodb提供了傻傻的两个函数,极傻无比。

limit()、skip()

db.student.find().limit(4).skip(4);

limit表示读取的条数,skip表示略过的条数,limit和skip配合使用就是分页查询。

加入,第一页是page=0。每页10条,所以当前页的查询语句

db.student.find({}).limit(10).skip(page*10)

能分页的个数

db.student.stats().count;

案例源代码:

db.js:

//这个模块封装了所有对数据库的常用操作。

const MongoClient = require('mongodb').MongoClient;

const settings = require('../settings');

//不管数据库什么操作,都是先连接数据库,所以我们可以把连接数据库

//封装成内部函数

function __connectDB(callback) {

var url = settings.dburl; //从settings文件中读数据库地址

MongoClient.connect(url, function (err, client) {

const db = client.db('huha');

//这里是新增加的

if (err) {

callback(err, db);

return;

}

callback(err, db, client);

});

};

//插入数据

exports.insertOne = function (collectionName, json, callback) {

__connectDB(function (err, db, client) {

if (err) {

callback(err, null);

return;

}

db.collection(collectionName).insertOne(json, function (err, result) {

callback(err, result);

client.close();//关闭数据库

});

})

};

//查找数据,找到所有数据

exports.find = function (collectionName, json, C, D) {

var result = [];//结果数组

if (arguments.length == 3) {

console.log("有三个参数");

//那么参数C就是callback,参数D没有传。

var callback = C;

var skipnumber = 0;

//数目限制

var limit = 0;

} else if (arguments.length == 4) {

console.log("有四个参数");

var callback = D;

var args = C;

//应该省略的条数

var skipnumber = args.pageamount * args.page;

//数目限制

var limit = args.pageamount;

} else {

throw new Error("find函数的参数个数,必须是3个,或者4个");

}

//连接数据库,连接之后查找所有

__connectDB(function (err, db, client) {

var cursor = db.collection(collectionName).find(json).skip(skipnumber).limit(limit);

cursor.each(function (err, doc) {

if (err) {

callback(err, null);

return;

}

if (doc != null) {

result.push(doc); //放入结果数组

} else {

//遍历结束,没有更多的文档了

callback(null, result);

}

});

client.close();

});

}

//删除

exports.deleteMany = function (collectionName, json, callback) {

__connectDB(function (err, db, client) {

if (err) {

callback(err, null);

return;

}

//删除

db.collection(collectionName).deleteMany(

json,

function (err, results) {

console.log(results);

client.close();

callback();

}

);

});

}

//修改

exports.updateMany = function (collectionName, json1, json2, callback) {

__connectDB(function (err, db, client) {

db.collection(collectionName).updateMany(

json1,

json2,

function (err, results) {

callback(err, results);

});

});

}

settings.js:

module.exports = {

"dburl": 'mongodb://localhost:27017'

}

02.js:

var express = require('express');

var app = express();

var db = require('./model/db.js')

//增加

app.get('/', function (req, res) {

db.insertOne("student", { "name": "小红", "age": 18 }, function (err, result) {

if (err) {

console.log("插入失败");

return;

}

res.send("插入成功");

});

});

//查询

app.get('/du', function (req, res) {

//这个页面现在接收一个page参数,

var page = parseInt(req.query.page); //express中读取get参数很简单

//查找4个参数,在哪个集合查,查什么,分页设置,查完之后做什么

db.find("student", {}, function (err, result) {

if (err) {

console.log(err);

}

res.send(result);

});

});

//删除

app.get('/shan', function (req, res) {

var name = parseInt(req.query.name);

db.deleteMany("teacher", { "name": "小红" }, function (err, result) {

res.send(result);

});

});

//修改

app.get("/xiugai", function (req, res) {

db.updateMany("student", { "name": "小红" }, { $set: { "name": "呼哈" } }, function (err, result) {

if (err) {

console.log(err);

}

res.send(result);

});

});

app.listen(3000);

项目—小小留言本

做一个留言本,能够增删改:

ejs页面中,如果我们想使用underscore的模板,就会有模板冲突的问题。

underscore用的:

<script type="text/template" id="moban">

<div class="list-group">

<a href="#" class="list-group-item
active">

<h4 class="list-group-item-heading"><%=xingming%>></h4>

<p class="list-group-item-text"><%=liuyan%></p>

</a>

</div>

</script>

ejs以为是自己的模板。所以报错,提示你没有传递姓名参数。

解决方法就是underscore源码。在源码中搜索<% 修改为{{即可。

项目整体目录结构:

03.js:

var express = require('express');

var app = express();

var db = require('./model/db.js');

var formidable = require('formidable');

var ObjectId = require('mongodb').ObjectId;

//设置模板引擎

app.set("view engine", "ejs");

//静态服务

app.use(express.static("./public"));

//显示留言列表

app.get("/", function (req, res, next) {

db.getAllCount("liuyanben", function (count) {

res.render('index', {

"pageamount": Math.ceil(count / 4)

});

});

});

//读取所有留言,这个页面是供ajax使用的

app.get("/du", function (req, res, next) {

//可以接受一个参数

var page = parseInt(req.query.page) || "0";

db.find("liuyanben", {}, { "sort": { "shijian": -1 }, "pageamount": 4, "page": page }, function (err, result) {

res.json({ "result": result });

});

});

//处理留言

app.post("/tijiao", function (req, res, next) {

console.log("对这里请求了");

var form = new formidable.IncomingForm();

form.parse(req, function (err, fields) {

//写入数据库

db.insertOne("liuyanben", {

"xingming": fields.xingming,

"liuyan": fields.liuyan,

"shijian": new Date()

}, function (err, result) {

if (err) {

res.send({ "result": -1 }); //-1是给ajax看的

return;

}

res.send({ "result": 1 });

});

console.log("收到请求了" + fields.xingming + fields.liuyan);

});

});

//得到总数量

app.get("/count", function (req, res) {

});

//删除

app.get('/shanchu', function (req, res, next) {

//得到参数

var id = req.query.id;

db.deleteMany("liuyanben", { "_id": ObjectId(id) }, function (err, result) {

res.redirect("/");

});

});

app.listen(3000);

settings.js:

module.exports = {

"dburl": 'mongodb://localhost:27017'

}

index.ejs:

<!doctype html>

<html lang="en">

<head>

<!-- Required meta tags -->

<meta charset="utf-8">

<meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="css/bootstrap.min.css">

<style>

.row h4 {

text-align: center;

}

#chenggong,

#shibai {

display: none;

}

.liuyankuai {

padding: 10px 0;

border-bottom: 1px solid #ccc;

}

</style>

<title>Hello, world!</title>

</head>

<body>

<h1>我的留言本</h1>

<div class="container">

<div class="row">

<form class="form-horizontal
col-lg-6">

<div class="form-group">

<label for="xingming" class="col-sm-2
control-label">姓名</label>

<div class="col-sm-10">

<input type="text" class="form-control" id="xingming" placeholder="姓名">

</div>

</div>

<div class="form-group">

<label for="inputPassword3" class="col-sm-2
control-label">留言</label>

<div class="col-sm-10">

<textarea style="resize:none;" name="liuyan" id="liuyan" class="form-control" rows="3"></textarea>

</div>

</div>

<div class="form-group">

<div class="col-sm-offset-2
col-sm-10">

<button type="button" id="tijiao" class="btn
btn-success">提交</button>

</div>

</div>

<div id="chenggong" class="alert
alert-success" role="alert">

<a href="#" class="alert-link">表单已经成功提交</a>

</div>

<div class="alert
alert-danger" id="shibai" role="alert">

<a href="#" class="alert-link">表单提交失败</a>

</div>

</form>

</div>

<nav aria-label="Page
navigation">

<ul class="pagination">

<% for(var i =1;i<=pageamount; i++){
%>

<li data-page="<%=i%>" class="yemaanniu">

<a href="#">

<%=i%>

</a>

</li>

<% } %>

</ul>

</nav>

<div id="quanbuliuyan">

</div>

</div>

<script type="text/template" id="moban">

<div class="liuyankuai">

<p>[_id]{{=id}}</p>

<p>[姓名]{{=xingming}}</p>

<p>[留言]{{=liuyan}}</p>

<p>[时间]{{=shijian}}</p>

<p><a href="/shanchu?id={{=id}}" class="shanchu" >删除</a></p>

</div>

</script>

<script src="js/underscore.js"></script>

<script src="js/jquery.min.js"></script>

<script>

var nowpage = 1;

//删除

//给第一个页面,补一个active

$(".pagination").find("li").eq(0).addClass("active");

//给所有的页码按钮,添加监听

$(".yemaanniu").click(function () {

nowpage = parseInt($(this).attr("data-page"));

//重新发起请求即可

getData(nowpage);

$(this).addClass("active").siblings().removeClass("active");

});

$("#nextbtn").click(function () {

nowpage++;

if (nowpage)

getData(nowpage);

});

//默认请求第一页数据

getData(1);

//Ajax请求数据

function getData(page) {

$.get("/du?page=" + (page - 1), function (result) {

//这里接收时result,但是这个json里面有一个key叫做result。

//得到模板,弄成模板函数

var compiled = _.template($("#moban").html());

//清空全部留言中的所有节点

$("#quanbuliuyan").html("");

for (var i = 0; i < result.result.length; i++) {

//数据绑定

var html = compiled({

liuyan: result.result[i].liuyan,

xingming: result.result[i].xingming,

shijian: result.result[i].shijian,

id: result.result[i]._id,

});

//DOM操作,添加节点

$("#quanbuliuyan").append($(html));

}

});

}

//Ajax提交表单

$("#tijiao").click(function () {

$("#shibai").hide();

$("#chenggong").hide();

//Ajax提交表单

$.post("/tijiao", {

"xingming": $("#xingming").val(),

"liuyan": $("#liuyan").val()

}, function (result) {

if (result.result == -1) {

$("#shibai").fadeIn();

} else if (result.result == 1) {

//提交成功

$("#chenggong").fadeIn();

//数据库真的存储了,但是当前页面无法显示,这是因为需要刷新

//才能用ajax从/du中得到新的。所以我们先用一个假盒子凑出来

var compiled = _.template($("#moban").html());

var html = compiled(

{

liuyan: $("#liuyan").val(),

xingming: $("#xingming").val(),

shijian: new Date()

}

);

console.log($("#quanbuliuyan"));

$(html).insertBefore($("#quanbuliuyan"));

}

});

});

</script>

</body>

</html>

db.js:

//这个模块封装了所有对数据库的常用操作。

const MongoClient = require('mongodb').MongoClient;

const settings = require('../settings');

//不管数据库什么操作,都是先连接数据库,所以我们可以把连接数据库

//封装成内部函数

function __connectDB(callback) {

var url = settings.dburl; //从settings文件中读数据库地址

MongoClient.connect(url, function (err, client) {

const db = client.db('huha');

//这里是新增加的

if (err) {

callback(err, db);

return;

}

callback(err, db, client);

});

};

//插入数据

exports.insertOne = function (collectionName, json, callback) {

__connectDB(function (err, db, client) {

if (err) {

callback(err, null);

return;

}

db.collection(collectionName).insertOne(json, function (err, result) {

callback(err, result);

client.close();//关闭数据库

});

})

};

//查找数据,找到所有数据

exports.find = function (collectionName, json, C, D) {

var result = [];//结果数组

if (arguments.length == 3) {

//  console.log("有三个参数");

//那么参数C就是callback,参数D没有传。

var callback = C;

var skipnumber = 0;

//数目限制

var limit = 0;

} else if (arguments.length == 4) {

//
console.log("有四个参数");

var callback = D;

var args = C;

//应该省略的条数

var skipnumber = args.pageamount * args.page || 0;

//数目限制

var limit = args.pageamount || 0;

//排序方式

var sort = args.sort || {};

} else {

throw new Error("find函数的参数个数,必须是3个,或者4个");

}

//连接数据库,连接之后查找所有

__connectDB(function (err, db, client) {

var cursor = db.collection(collectionName).find(json).skip(skipnumber).limit(limit).sort(sort);

cursor.each(function (err, doc) {

if (err) {

callback(err, null);

return;

}

if (doc != null) {

result.push(doc); //放入结果数组

} else {

//遍历结束,没有更多的文档了

callback(null, result);

}

});

client.close();

});

}

//删除

exports.deleteMany = function (collectionName, json, callback) {

__connectDB(function (err, db, client) {

if (err) {

callback(err, null);

return;

}

//删除

db.collection(collectionName).deleteMany(

json,

function (err, results) {

console.log(results);

callback(null,results);

client.close();

}

);

});

}

//修改

exports.updateMany = function (collectionName, json1, json2, callback) {

__connectDB(function (err, db, client) {

db.collection(collectionName).updateMany(

json1,

json2,

function (err, results) {

callback(err, results);

//这里可能会有错误

client.close();

});

});

}

//得到文件总数

exports.getAllCount = function (collectionName, callback) {

__connectDB(function (err, db, client) {

var a = db.collection(collectionName).count({}).then(function (count) {

//  console.log(count);

callback(count);

client.close();

});

});

}

二、Cookie和Session

HTTP是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页面,服务器无法认识到,这是同一个浏览器在访问同一个页面。每一次的访问,都是没有关系的。

那么世界就乱套了,比如说我上一次访问,登陆了,下一次访问,又让我登录,不存在登录着事儿了。

第一次访问一个服务器,不可能携带cookie。必须是服务器得到这次请求,在下行的响应报头中携带cookie信息,此后每一次浏览器往这个服务器发出的请求,都会携带这个cookie。

·cookie是不加密的,用户可以自由看到;

·用户可以删除cookie,或者禁用它

·cookie可以被篡改

·cookie可以用于攻击

·cookie存储量很小。未来实际上要被localStorage干掉。

express中的cookie,你肯定能想到。res负责设置cookie,req负责识别cookie。

Express中的Cookie

·Express中,使用cookie-parser中间件来设置cookie.

·主要设置选项:domain、path、maxAge、signed

1.js:

var express = require('express');

var cookieParser = require('cookie-parser');

var app = express();

app.use(cookieParser());

app.get('/', function (req, res) {

res.cookie('xihao', 'tfboys', { maxAge: 900000, httpOnly: true })

res.send();

});

app.listen(3000);

这个图是服务器发给浏览器的cookie,是明码:

再次请求的时候可以看到浏览器携带的cookie,是明码。

test.js:

var express = require('express');

var cookieParser = require('cookie-parser');

var app = express();

//使用cookie必须要使用cookie-parser中间件

app.use(cookieParser());

app.get('/', function (req, res) {

//maxAge在Express中毫秒为单位

// res.cookie('xihao', 'tfboys', { maxAge: 900000, httpOnly: true })

res.send("猜你喜欢" + JSON.stringify(req.cookies));

});

app.get("/gonglue", function (req, res) {

//得到get请求,用户查询的目的地

var mudidi = req.query.mudidi;

//记录用户喜好

//先读取用户的喜好,然后把新的数据push进入数组,设置新的数据

var mudidiarray = req.cookies.mudidi || [];

mudidiarray.push(mudidi);

res.cookie("mudidi", mudidiarray, { maxAge: 900000, httpOnly: true });

res.send(mudidi + '旅游攻略');

});

app.listen(3000);

4.2 Session

Session不是天生就有的,是依赖于cookie。

cookie是明码传输的,

浏览器通过给服务器发送一段”乱码”cookie,让服务器进行对比,看看这个客户端是谁。

session依赖cookie,当一个浏览器禁用cookie的时候,登陆效果消失;或者用户清除了cookie,登录也消失。

session比cookie不一样在哪里呢? session下发的是乱码,并且服务器自己缓存一些东西,下次浏览器的请求带着乱码上来,此时与缓存进行比较,看看是谁。

所以,一个乱码,可以对应无限大的数据。

任何语言中,session的使用,是”机理透明”的,他是帮你设置cookie的,但是足够方便,让你感觉不到这事儿和cookie有关。

session中乱码和存储数据比对的这个库是存储在服务器的内存中的,一旦服务器关机了,就会消失了。

nodejs中的session:

express中使用express-session来使用session。

05.js:

var express = require('express');

var app = express();

var session = require('express-session');

app.use(session({

secret: 'keyboard cat',

resave: false,

saveUninitialized: true,

}));

app.get('/', function (req, res) {

if (req.session.login == "1") {

res.send("欢迎你");

} else {

res.send('你没有登陆!!');

}

})

app.get('/login', function (req, res) {

req.session.login = "1"; //设置这个session

res.send('你已经成功登陆');

});

app.listen(3000);

看看这段被加密的cookie:

做一个利用session的登陆界面:

var express = require('express');

var app = express();

var db = require('./model/db.js');

var session = require('express-session');

app.use(session({

secret: 'keyboard cat',

resave: false,

saveUninitialized: true,

}));

app.set('view engine', 'ejs');

app.get('/', function (req, res) {

if (req.session.login == "1") {

res.send("欢迎" + req.session.username);

} else {

res.send("没有成功登录");

}

});

app.get('/login', function (req, res) {

res.render('denglu');

});

app.get('/checklogin', function (req, res) {

var tianxiedeusername = req.query.username;

var tianxiepassword = req.query.password;

//根据用户填写的姓名,去数据库里面找这个文档,读出密码

//如果读取的密码,和填写的密码一样,那么登录成功了

//如果读取的密码和填写的密码不一样,登陆失败.

//如果根本没有找到这个记录,那么就说明用户名填写错了

db.find("users", { "username": tianxiedeusername }, function (err, result) {

console.log(result);

if (result.length == 0) {

res.send('你的登录名写错了,没有这个注册用户');

return;

}

var shujukuzhongdepassword = result[0].password;

if (shujukuzhongdepassword == tianxiepassword) {

req.session.login = "1";

req.session.username = result[0].username;

res.send('成功登录!你是' + result[0].username);

} else {

res.send('用户名对了密码错误');

}

});

});

app.listen(3000);

加密使用的是MD5加密。

加密’1’:

md5(1,32) = c4ca4238a0b923820dcc509a6f75849b
md5(1,16) = a0b923820dcc509a

加密’2’:

md5(2,32) = c81e728d9d4c2f636f067f89cc14862c
md5(2,16) = 9d4c2f636f067f89

不管你加密多大的东西,哪怕10M的文字,都会加密为32位的字符串,就是密码。并且神奇的,数学上能够保证,哪怕你更改一个文字,都能大变。

MD5是数学上,不能破解的。不能反向破解。

也就是说,c4ca4238a0b923820dcc509a6f75849b 没有一个函数,能够翻译成为1的。

但是,有的人做数据库就是把1~999999所有数字都用MD5加密了,然后进行了列表,所以有破解的可能。

Node_进阶_5的更多相关文章

  1. Node_进阶_8

    Node进阶第八天 一.复习 Node.js特点:单线程.异步I/O(非阻塞I/O).事件驱动(事件环). 适合的程序:就是没有太多的计算,I/O比较多的业务. 举例:留言本.考试系统.说说.图片裁切 ...

  2. Node_进阶_7

    Node进阶第七天 一.复习 一.索引   数据库中,根据一个字段的值,来寻找一个文档,是很常见的操作.比如根据学号来找一个学生.这个学号是唯一的.只要有学号,就能唯一确认一个学生的文档.学号这个属性 ...

  3. Node_进阶_6

    Node进阶第六天 一.复习 cookie是在res中设置,req中读取的.第一次的访问没有cookie. cookie的存储大小有限,kv对儿.对用户可见,用户可以禁用.清除cookie.可以被篡改 ...

  4. Node_进阶_4

    Node进阶第四天 一.传统数据库技术回顾 数据库就是存储数据的,那么存储数据用txt就行了啊,为什么要有数据库? 理由之一:数据库有行.列的概念,数据有关系,数据不是散的. 老牌数据库,比如Mysq ...

  5. React-Native进阶_5.导航 Naviagtion

    有这样一个组件 他可以控制页面跳转 返回,在移动端叫做导航控制器, 在RN中叫路由 我们使用的  react-native-navigation 是一个开源组件库介绍:A complete nativ ...

  6. Node_进阶_2

    第二天 一.复习: Node.js开发服务器.数据.路由.本地关心效果,交互. Node.js实际上是极客开发出的一个小玩具,不是银弹.有着别人不具备的怪异特点: 单线程.非阻塞I/O.事件驱动. 实 ...

  7. Node_进阶_1

    第一天 1.1简介 Node.js简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,Ryan Dahl把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个让Javascrip ...

  8. Node_进阶_3

    Express框架: 一.   Express框架 Express框架是后台的Node框架,类似于JS中的jquery. #原生Node开发会有很多问题: 1呈递静态页面很不方便,需要处理每个HTTP ...

  9. PythonI/O进阶学习笔记_5.python的set和dict

    前言: 我一直觉得对我来说学习知识很忌讳不系统.本篇内容与上一篇 自定义序列类是有联系的. 上一篇比较通范的了解了序列类的一些协议和特性,并且有些list的内容.这篇更加具体到set和dict这两个序 ...

随机推荐

  1. uploadifive上传文件

    uploadifive是一个款基于H5的上传文件的插件.优点是,可以在PC端,也可以在手机上进行操作.缺点是,IE9以下的兼容性不好. View: <!DOCTYPE html> < ...

  2. swift使用查阅资料备份4

    Swift - RxSwift的使用详解6(观察者2: 自定义可绑定属性) http://www.hangge.com/blog/cache/detail_1946.html extension UI ...

  3. selenium基础

    浏览器 selenium本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转.输入.点击.下拉等来拿到网页渲染之后的结果,可支持多种浏览器 官网链接:http://selenium-python.re ...

  4. 动态生成的dom元素绑定事件

    要求:要绑定到父元素上$(".school_Inlists").on("click",".chose_Inbtn",function(){ ...

  5. 堆————数据流的第k个大的元素

    解题思路 一般地,堆和堆排序——解决 "贪心算法及其类似问题" 的利器. # 思路:我们可以用一个小根堆来做,并且限制堆的大小为k,初始化时把nums的每个数都push到堆中,如果 ...

  6. Pyhton学习——Day50

    #HTTP协议# 又是转载:http://www.cnblogs.com/yuanchenqi/articles/6000358.html# 一 HTTP概述# HTTP(hypertext tran ...

  7. [NOIP补坑计划]NOIP2016 题解&做题心得

    感觉16年好难啊QAQ,两天的T2T3是不是都放反了啊…… 场上预计得分:100+80+100+100+65+100=545(省一分数线280) ps:loj没有部分分,部分分见洛咕 题解: D1T1 ...

  8. 洛谷4623 [COCI2012-2013#6] BUREK

    题目描述 给定N个三角形,和M条直线,直线要么平行于X轴,要么平行于Y轴,问这M条直线 分别经过多少个三角形内部 (注意是内部即分开的两个多边形的面积均大于零). 输入输出格式 输入格式: 第一行一个 ...

  9. python 面向对象 类的内置方法

    判断是不是类cls的对象 class A: pass a = A() print(isinstance(a,A)) 判断类sub是不是super的子类 class A: pass class B(A) ...

  10. GitHub上传项目,使用desktop(客户端)教程

    GitHub上传项目,使用desktop(客户端)教程  搜索“GitHub上传项目”,能得到很多相关的文章教程,里面讲的都特别麻烦,要弄什么ssh之类的,可算是吓坏了我,使我非常的怀疑为什么GitH ...