commit 0207414c505d99c094750a565e67ae6d736d4ceb Author: Isaac <3388214266@qq.com> Date: Fri Feb 13 23:38:38 2026 +0800 init diff --git a/imgs/QQ_1758351896772.png b/imgs/QQ_1758351896772.png new file mode 100644 index 0000000..5d0a3ed Binary files /dev/null and b/imgs/QQ_1758351896772.png differ diff --git a/imgs/image-20250601215956519.png b/imgs/image-20250601215956519.png new file mode 100644 index 0000000..7b941a4 Binary files /dev/null and b/imgs/image-20250601215956519.png differ diff --git a/imgs/image-20250601220104712.png b/imgs/image-20250601220104712.png new file mode 100644 index 0000000..a3d5ce8 Binary files /dev/null and b/imgs/image-20250601220104712.png differ diff --git a/imgs/image-20250601220355280.png b/imgs/image-20250601220355280.png new file mode 100644 index 0000000..433a810 Binary files /dev/null and b/imgs/image-20250601220355280.png differ diff --git a/imgs/image-20250601220658402.png b/imgs/image-20250601220658402.png new file mode 100644 index 0000000..0b66047 Binary files /dev/null and b/imgs/image-20250601220658402.png differ diff --git a/imgs/image-20250601220748017.png b/imgs/image-20250601220748017.png new file mode 100644 index 0000000..8b47b6a Binary files /dev/null and b/imgs/image-20250601220748017.png differ diff --git a/imgs/image-20250606171956311.png b/imgs/image-20250606171956311.png new file mode 100644 index 0000000..af58fcb Binary files /dev/null and b/imgs/image-20250606171956311.png differ diff --git a/imgs/image-20250606214847373.png b/imgs/image-20250606214847373.png new file mode 100644 index 0000000..a332cb1 Binary files /dev/null and b/imgs/image-20250606214847373.png differ diff --git a/imgs/image-20250918195657365.png b/imgs/image-20250918195657365.png new file mode 100644 index 0000000..3c1869c Binary files /dev/null and b/imgs/image-20250918195657365.png differ diff --git a/imgs/image-20250918195700453-1758196624047-1-1758196625750-3.png b/imgs/image-20250918195700453-1758196624047-1-1758196625750-3.png new file mode 100644 index 0000000..3c1869c Binary files /dev/null and b/imgs/image-20250918195700453-1758196624047-1-1758196625750-3.png differ diff --git a/imgs/image-20250918195700453-1758196624047-1.png b/imgs/image-20250918195700453-1758196624047-1.png new file mode 100644 index 0000000..3c1869c Binary files /dev/null and b/imgs/image-20250918195700453-1758196624047-1.png differ diff --git a/imgs/image-20250918195700453.png b/imgs/image-20250918195700453.png new file mode 100644 index 0000000..3c1869c Binary files /dev/null and b/imgs/image-20250918195700453.png differ diff --git a/imgs/image-20250925180747838.png b/imgs/image-20250925180747838.png new file mode 100644 index 0000000..f9de54e Binary files /dev/null and b/imgs/image-20250925180747838.png differ diff --git a/imgs/image-20251108205923125.png b/imgs/image-20251108205923125.png new file mode 100644 index 0000000..def578b Binary files /dev/null and b/imgs/image-20251108205923125.png differ diff --git a/imgs/image-20251108205944930.png b/imgs/image-20251108205944930.png new file mode 100644 index 0000000..68df8d0 Binary files /dev/null and b/imgs/image-20251108205944930.png differ diff --git a/imgs/image-20251108205954246.png b/imgs/image-20251108205954246.png new file mode 100644 index 0000000..9695ef0 Binary files /dev/null and b/imgs/image-20251108205954246.png differ diff --git a/imgs/image-20251108210015132.png b/imgs/image-20251108210015132.png new file mode 100644 index 0000000..4f8764c Binary files /dev/null and b/imgs/image-20251108210015132.png differ diff --git a/imgs/image-20251108210030562.png b/imgs/image-20251108210030562.png new file mode 100644 index 0000000..e91a8e5 Binary files /dev/null and b/imgs/image-20251108210030562.png differ diff --git a/imgs/image-20251108210036792.png b/imgs/image-20251108210036792.png new file mode 100644 index 0000000..6511045 Binary files /dev/null and b/imgs/image-20251108210036792.png differ diff --git a/imgs/image-20251108210057428.png b/imgs/image-20251108210057428.png new file mode 100644 index 0000000..4a4ab4a Binary files /dev/null and b/imgs/image-20251108210057428.png differ diff --git a/imgs/image-20251108210112098.png b/imgs/image-20251108210112098.png new file mode 100644 index 0000000..cecc995 Binary files /dev/null and b/imgs/image-20251108210112098.png differ diff --git a/imgs/image-20251108210130819.png b/imgs/image-20251108210130819.png new file mode 100644 index 0000000..d4df095 Binary files /dev/null and b/imgs/image-20251108210130819.png differ diff --git a/imgs/image-20251108210146788.png b/imgs/image-20251108210146788.png new file mode 100644 index 0000000..1afdca4 Binary files /dev/null and b/imgs/image-20251108210146788.png differ diff --git a/imgs/image-20251108210159459.png b/imgs/image-20251108210159459.png new file mode 100644 index 0000000..e6ad66f Binary files /dev/null and b/imgs/image-20251108210159459.png differ diff --git a/imgs/image-20251108210222716.png b/imgs/image-20251108210222716.png new file mode 100644 index 0000000..752de4d Binary files /dev/null and b/imgs/image-20251108210222716.png differ diff --git a/imgs/image-20251108210235815.png b/imgs/image-20251108210235815.png new file mode 100644 index 0000000..60b731a Binary files /dev/null and b/imgs/image-20251108210235815.png differ diff --git a/imgs/image-20251202135729648.png b/imgs/image-20251202135729648.png new file mode 100644 index 0000000..334aec8 Binary files /dev/null and b/imgs/image-20251202135729648.png differ diff --git a/imgs/image-20251205141751423.png b/imgs/image-20251205141751423.png new file mode 100644 index 0000000..71acb27 Binary files /dev/null and b/imgs/image-20251205141751423.png differ diff --git a/imgs/image-20260102104729767.png b/imgs/image-20260102104729767.png new file mode 100644 index 0000000..4339627 Binary files /dev/null and b/imgs/image-20260102104729767.png differ diff --git a/imgs/image-20260102110324837.png b/imgs/image-20260102110324837.png new file mode 100644 index 0000000..2e6e27a Binary files /dev/null and b/imgs/image-20260102110324837.png differ diff --git a/三角机构/ARC.pdf b/三角机构/ARC.pdf new file mode 100644 index 0000000..a0931a0 Binary files /dev/null and b/三角机构/ARC.pdf differ diff --git a/三角机构/image-20251114112539697.png b/三角机构/image-20251114112539697.png new file mode 100644 index 0000000..58c0447 Binary files /dev/null and b/三角机构/image-20251114112539697.png differ diff --git a/三角机构/image-20251120225604227.png b/三角机构/image-20251120225604227.png new file mode 100644 index 0000000..241adda Binary files /dev/null and b/三角机构/image-20251120225604227.png differ diff --git a/三角机构/三角期刊/三角时报永恒之泉.pptx b/三角机构/三角期刊/三角时报永恒之泉.pptx new file mode 100644 index 0000000..f541592 Binary files /dev/null and b/三角机构/三角期刊/三角时报永恒之泉.pptx differ diff --git a/三角机构/三角期刊/三角时报路霸(1)/三角时报路霸.png b/三角机构/三角期刊/三角时报路霸(1)/三角时报路霸.png new file mode 100644 index 0000000..cca4cda Binary files /dev/null and b/三角机构/三角期刊/三角时报路霸(1)/三角时报路霸.png differ diff --git a/三角机构/三角期刊/三角时报路霸(1)/三角时报路霸.pptx b/三角机构/三角期刊/三角时报路霸(1)/三角时报路霸.pptx new file mode 100644 index 0000000..0f8c9ba Binary files /dev/null and b/三角机构/三角期刊/三角时报路霸(1)/三角时报路霸.pptx differ diff --git a/三角机构/三角期刊/三角时报路霸(1)/路霸.pdf b/三角机构/三角期刊/三角时报路霸(1)/路霸.pdf new file mode 100644 index 0000000..e550fe3 Binary files /dev/null and b/三角机构/三角期刊/三角时报路霸(1)/路霸.pdf differ diff --git a/三角机构/三角期刊/三角时报路霸(1)/路霸.png b/三角机构/三角期刊/三角时报路霸(1)/路霸.png new file mode 100644 index 0000000..0fabd96 Binary files /dev/null and b/三角机构/三角期刊/三角时报路霸(1)/路霸.png differ diff --git a/三角机构/三角洲经理.md b/三角机构/三角洲经理.md new file mode 100644 index 0000000..667e723 --- /dev/null +++ b/三角机构/三角洲经理.md @@ -0,0 +1,221 @@ + + +# 开场白 + + + +宇宙本不应被观测。观测产生思想; 思想塑造现实。 大量相似思想的累积,或一个尤为强 大的单一思想,都可能对正确与真实 之物造成非自然的扭曲。我们将这些 扭曲称为异常体。 异常体极其危险。它们必须被捕获并 收容,以免其在现实中撕开缺口, 使我们暴露于任何凡俗心智都无法想象的、远为强大的力量面前。三角机构,一家为公共利益服务的私营企业,挺身应对此项挑战。 + + + +我们的宇宙承载着许多相互竞争的利益。尽 管我们正努力提高这一数字,但三角机构目前在现实中所占的股份约为25% 所以我们投的是四面头。 + +幸运的是,在其他的五个已知的未来中,我们占据 了整个市场 因此我们可以投掷6个四面头。 + + + + + +异常的构成 焦点 领域 + + + +普通手提箱 + + + +波纹枪 3申惩 + +19-22 24 26 + + + +> 如何对付异常 + +暂时满足其焦点(使其心满意足) + +说服它其行为适得其反(使其陷入困惑) + +移除其焦点的来源(使其陷入绝望) + + + +> 福利 + +1. 特工可自动消耗每点伤害1点资质保证来无视该伤害的效果。具体的资质无关紧要。攻击或效果仍然会作用于您,旁观者也会看到其发生,但机构会将该伤害的结果转移到别处。别担心:您什么也感 觉不到 +2. 他们将进入嘉奖负债状态。通过获得嘉奖,直到特工 的总数达到零或以上,嘉奖负债便会移除。 处于嘉奖负债状态的特工将被自动纳入鞋带倡议,其鞋带会不时地自动 松开,作为一种温和的提醒,督促其脱离嘉奖负债状态。如果您通常不 穿带鞋带的鞋子,请将鞋带系在您身体的某个部位,以便体验该倡议的 全部益处 + +1. 若复活一名特工不再符合成本效益,三角机构将为您的亲人 提供一小笔抚恤金和一份保密协议 + + + +# 冰淇淋 + +## 可选目标 + +吃一碗幸运饼干 +1嘉奖 + +在他人面前/让他人展示出少女心 +3嘉奖(每人一次) + +禁止说带有“好”的字 +3申戒 + +## 路上事件 + +- 人发现三角城最近举办了一场盛大的马拉松,所有人都在满怀笑意的进行这跑步,但似乎这场马拉松你上个月就已经在举行了 +- B发现上学的学生们一脸死气沉沉的走在路上 +- C上班路上看到一辆车偏离了车道。 --》无论如何,当事情 平息后,他们瞥见了原因:司机已经冻僵了,被 一层薄冰包裹着。他死了。 + +## 开会 + +最近城市有大量的人被气场冻结 + + + + + + + + + +## 入场(练手) + +你们去泳池派对 但是门口有保安 你们该如何进去呢? + + + +## 进去以后 + +### 找目标 + +- 冰淇淋车 +- 询问了路人 + + + + + +### 衣服不合身 + + + + + + + +### 有人吃了冰淇凌冻住了 + + + + + + + + + +## **特殊规则:** + +如果他们拿走任何零食并食用或使用,异常的特殊规则将启动:如果在任何时候他们的脉搏或体温显著升高,他们会开始冻结。最初这种感觉仿佛是一种巨大的解脱,但随后却会致命。对于特工而言,这表现为 2 点伤害,他们可以尝试使用能力或素质保证来避免这一效果。若他们开始奔跑或出汗,请务必提醒他们这一点。 + + + + + +## 焦点 + +解救炎热。这辆异常正借着冻结开始的那一刻汲取力量,但它不明白完全冻结人们并非必要。每当你觉得他们已安定下来,就开始冻结那些处于明显炎热情境中的人:晒太阳的人、在泳池旁奔跑的人、穿着过多衣物的人。那些刚才大声抱怨热的人?现在他们却冻得笑容满面。 + + + + + +## **领域:** + +冰淇淋车的内部。特工们可以利用自己的能力进入车内,或者设法欺骗异常:如果他们大声抱怨太热,但又有理由拒绝享用零食,异常就会打开车门,让他们进入那冰冷的内部。记住,在内部混沌消耗的价值是原来的三倍。 + + + + + + + +# 死寂 + + + +## 晨会 + +- 一位重要之人原计划去深夜酒馆跳舞, 但活动被取消了。又一次。 +- 特工的电视在播放他们最喜欢的节目时反复 静音,然后显示出小众街机游戏《太鼓达人》 的开场画面。 +- 一名特工不断在奇怪的地方发现扑克牌。这 些牌总是人头牌,而且牌上的人脸似乎总是 在尖叫。 +- 一位重要之人在一次重要活动前夕失声了。 +- 一名特工正要出门时,被电脑或其他设备的 电线绊倒,那些电线仿佛凭空出现一般。 + +## 任务简报 + + 两周前,一个名为凯迪角的社区内报告了一起死 亡事件。当地一家名为双杰的酒吧老板之 一Tony Jackson被发现时,脸上凝固着痛苦的 表情,嘴巴张开仿佛在尖叫–,但死亡原因似乎 是突发性心脏骤停。 + + 上周,又报告了另一起死亡事件———一名 叫Manny Navarro的年轻男子在当地一家名为 Laundrocade的店铺里被发现,状态与前者相 同。 + + 这一巧合引起了机构的注意,并由此引出了 最新的发现: 凯迪角的居民们并不知道,昨晚在社区外又发现 了一具尸体———一名二十多岁的女性,表情与 前两名死者相同,身旁放着一袋金工工具。尸体 已死亡约一个月,是在对附近一块待开发土地进 行勘测时发现的。警方尚未开始调查她的身份, 而要确定其身份将十分困难。 + + 有什么东西正在那个社区里杀人,而机构希望在 谣言引起人们对异常体活动的关注之前,查明真相 + + + +## 外观 + +一个由纤细骨骼构成的牢笼,如同耳骨在装扮成 人形。从远处看,这个异常体可能像一具四肢修 长的骷髅:它白色、毫无特征的头部栖于蜂巢状 的身体之上,其身体之大,足以将一个人类包裹 于其核心之中。 + +凑近观察会发现,异常体的手臂和腿没有真正的 关节,像老旧的电话线一样无力地从其核心垂 下。当它直立时,与其说是在行走,不如说只是 单纯地出现在更近的地方。当它四肢着地时,它 像狼一样向前跳跃,金属丝般的四肢在触及每一 寸新地面时伸长又缩短。 + + + + + +## 双杰酒馆 + +凯迪角的社区酒吧双杰酒馆,坐落在一栋低矮的砖砌建筑里,门上挂着一块简单的招牌。一块 用管道胶带粘在上面的手绘横幅写着“本市友好度第三的酒吧!”门外,一块黑板招牌的一面列出 了一周的活动,包括周一开放麦、周三单身派对之夜(特邀三手玫瑰乐队)以及DJ周五摇摆夜,所有这些活动都被划掉,并潦草地写上了“已取消”的字样。黑板的另一面写着“纪念l老杰最初的红心J。” + + + +### 入口 + +双杰的门是一扇老旧的木门,顶部有个小 窗,曾被漆成扑克牌的模样,但大部分油漆已经 剥落。门上贴满了各种告示。 一张贴了太多免费剪贴画的广告:“汗流浃背? 臭气熏天?满身啤酒?快来刘艳洗衣, 每月可获赠价值5美元的街机代币!” 一张旧的街区派对传单:“本周末,The Station火力全开—6家本地摊贩,DJ泰迪G带来 劲爆音乐,还有比莉的全新金属雕塑!派对直到 黄昏! + + + +### 主厅 + +双杰是一家老派的廉价酒吧,灯光昏暗, 角落阴影重重,地板发粘,木制家具的清漆正 在剥落。它比外面看起来要大,从房间右侧的吧 台一直延伸到一个中央木制舞池,舞池旁有一个 小DJ台,需要时可作为舞台。舞池尽头是卫生 间,旁边一扇门上标着“办公室”。除了酒吧工 作人员,里面只有寥寥几名顾客。士气低落。 + + + +### 谢酒保 + + 谢能调制出他尝过的任何一种 饮品。他二十多岁时喝遍了各大酒吧,因此酒单 储备极为丰富,不过他总在寻求扩充。最近成了 品茶鉴赏家。他怕虫子怕得要死,所以总想在不 失廉价酒吧氛围的前提下,把店里打扫得尽可能 干净。两周前托尼死在吧台后,他一直急着想把 那里彻底打扫一遍(只要能得到杰姬的允许)。 特工们抵达时,他正在离门最远的半边吧台后工 作。另一半吧台已被封锁;那里是托尼死去的地 方。 + +特工们可以通过点单并与谢里夫交谈,了 解到以下信息: + + 托尼值夜班时总是喝根汁汽水。 + +卫生间里有个看起来像蜘蛛的东西在动。 那东西让他感觉很不好,但总是在被抓住 前就飞快地溜走了。 + + + + + +### 舞池 + +舞池后方有一个小DJ台,里面放着音响系统。 没人试着去修理它。靠近音响系统会让人感 觉毛骨悚然。 使用追踪异常共鸣的方法会发现一条微弱的踪迹 从音响通往卫生间,一条明显的踪迹通往吧台后 托尼死去的地方,然后延伸至前门,并在那里消 散得无法追踪。 + + + +### 卫生间 + +进入卫生间需要从杰姬或谢里夫那里拿到钥匙。 里面是一个单间和一些老派的卫生间涂鸦。一 个由双杰音响电线制成的线灵正蹲在角落 里,像一只长腿蜘蛛。 如果被接近或对峙,它会逃到主厅(如果有足够 的混沌,则会变为闪电线灵),并攻击酒吧工作 人员和顾客,很可能会制造出散逸端。 + + + +### 杰姬 + +杰姬曾是一名爵士歌 手,后来她那沙哑的嗓音不知是因为开始吸烟还 是戒烟而消失了———她的说法每次都不同。她 和前夫共同拥有双杰近20年。所有人都以 为酒吧的名字取自他们俩的名字,但实际上是她 在一次二十一点牌局中从前任老板手里赢来的。 大约两周前,她发现了死在吧台后地板上的托 尼,他嘴巴张开,仿佛在尖叫。杰姬坚信是某种 东西杀死了托尼。 特工们抵达时,她正在酒吧的办公室里(一间位 于卫生间后方、没有窗户的小房间,墙上贴满了 扑克牌)处理他死后产生的一些文书工作。她偶 尔会出来找谢里夫要冰茶,并向他抱怨没人把托 尼或曼尼·纳瓦罗的死当回事。 杰姬希望市政能对她收集到的所有关于托尼之死 的证据进行官方调查,并希望能在坏掉的音响上 再听一次他最喜欢的歌曲《两张J换一张Q》。 diff --git a/三角机构/以撒的结合.md b/三角机构/以撒的结合.md new file mode 100644 index 0000000..434f9e8 --- /dev/null +++ b/三角机构/以撒的结合.md @@ -0,0 +1,339 @@ + + + + + + +# 异常体档案 罪恶 + + + + + +| 值 | 名称 | 效果(供KP叙述与判定) | +| ---- | ---------- | ------------------------------------------------------------ | +| 2 | 腐化 | **苹果中的剃刀**:任意一名最近“获得好意”的目标,在吃东西或喝水时,发现口中出现异物——如玻璃碎片、剃刀片、针等。造成1伤害 | +| 3 | 现实触发器 | **罪的重演**:目标周围出现与以撒记忆相似的小细节——教室里多出一张他从未画过的“被欺负”的画、母亲责备的耳语、赌徒的笑声等。首次发生时,所有在场特工进行一次低难度理智检定,失败者会在片刻间坚信:**“我以前也这样伤害过别人 / 被这样伤害过。”** | +| 5 | 吸引 | **拜访以撒**:镇民(或重要之人)开始做同一个梦:他们爬上山,来到以撒的房间,对着箱子倾诉自己的罪,醒来时记不清细节,只记得很累。KP可借此安排 NPC 主动来“找以撒”,把线索送上门。 | +| 6 | 双重 | **暴食 & 贪婪(次级异常)**:在场中随机两人各被附着一个次级异常: · 暴食:每隔数轮(现实中 2 分钟左右),必须用一个行动吃东西、喝酒、吞药等;若无法满足,则受1伤害,并产生失控暴食行为。 · 贪婪:强迫性地想把所有金币、小物件、甚至他人的装备收入囊中。拒绝则受1伤害。 | +| 8 | 扩张 | **以撒化**:异常开始迅速扩散。越来越多的居民(甚至特工)出现“以撒化”症状: · 文件里名字被改成“以撒”; · 镜子里看到的是以撒的脸; · 他人的记忆会被“修正”为:**“你一直是那个带来不幸的人。”** 若不遏制,整个镇会逐渐变成一个由无数个“以撒”组成的伪家庭。 | +| 9 | 三重 | **四骑士复苏**:以撒的“四骑士”以四种场景或NPC形态出现,可分配给四个不同的人或地点: · 战争:某人突然极度暴力,对小事大发雷霆,随时动手; · 瘟疫:某人皮肤溃烂、高烧不退,医检无明确原因; · 饥荒:大量食物瞬间腐烂、长蛆;与“暴食”组合时形成可怕的“吃腐烂物冲动”; · 死亡:环境本身变得致命,“稍有不慎就会暴毙”(楼梯塌陷、车祸、坠物等)。 | +| 10 | 抹杀 | **妈腿**:一条异样粗大、臃肿、带着裙边的女性腿,从天花板轰然砸下,对目标造成高额3伤害。被砸中的人还会听到母亲的尖叫与祷告在脑内回荡。 | +| 30 | 罪我 | **终极自责**:特工彻底被异常吞噬,产生强烈的信念: “这一切的一切,都是因为我。如果我从世界上消失,就能结束。”该目标会尝试以任何方式让自己“被抹去”(可以是自残、自我牺牲冲向异常核心,被箱子收入等,由 KP 用剧情方式呈现),并将自己一起投喂给宝箱。``几乎无法避免`` | +| | | | + +## 晨会 + +可从中挑 1–2 条作为开场预兆: + +- 一名特工的好友因赌博欠下一屁股债,被高利贷追着跑,嘴里一直念叨: + + > “要不是我孩子出生,我也不会这么穷……” + +- 一名特工突然**异常想念自己的母亲**,甚至在简报时走神,脑中反复闪回童年被责骂或被保护的画面。 + +- 某特工的手机随机弹出一条新闻推送: + + > “山顶小屋男童十年前失踪案——警方认定为家庭纠纷后离家出走。” + > 配图是一座孤零零的房子和模糊的小男孩背影。 + +## 历史 + +**· 赌场线索(父亲)** + +- 赌场老板和常客会提到:以撒的父亲是这里的常客, + - 经常偷家里钱来赌博,连儿子的储蓄罐都砸了; + - 欠下一屁股债后消失,有人说他“卷钱跑路”,有人说他“被人做掉了”。 +- 特工可以在赌场获得: + - 父亲的名字、旧照片; + - 账本里他名字边上被画上的小十字架和涂黑痕迹(暗示他对家中“罪”的贡献)。 + +**· 教堂线索(母亲)** + +- 神父会承认: + + - 以撒母亲长期遭受丈夫语言与肢体暴力; + - 在丈夫离开后精神崩溃,整天看宗教电视节目,坚称自己“听见上帝要她净化孩子”。 + +- 教堂资料室里可以找到**母亲的忏悔书原件**,边角沾有药粉和泪痕。 + +- 老教友会说: + + > “她常说,以撒是天生的坏种,是罪的源头。” + +**· 学校线索(欺凌)** + +- 老教师或同学会提到: + - 没人愿意和以撒同桌; + - 他的东西经常被藏、被丢; + - “那孩子总是道歉,什么都说是自己的错。” +- **走廊墙绘**就是关键证据: + - cv一整面墙被儿童画覆满,以撒被各种方式欺负、塞进柜子,被画成“坏事的影子”; + - 还有那一幅**女孩递苹果给以撒**的画,旁边有人涂写:“他活该”。 + +**· 苹果与剃刀事件(异常的起点)** + +- 以撒曾经好不容易得到一个女孩送的苹果; + +- 咬下去时,发现里面埋着一片剃刀片,**嘴被划烂,满嘴是血**; + +- 老师只是让他“以后吃东西小心点”,没有追究是谁干的; + +- 那天之后,以撒开始彻底相信: + + > “连好意和礼物也是带着刀的,是因为我该受罚。” + + + +## 焦点 + +**以撒**与“罪”的认知: + 他真心相信——家庭所有的不幸、争吵、暴力和离散,**都是因为他**。 + 在异常看来,**任何把一切过错都扛到自己身上的人,都可以成为“新的以撒”**。 + +## 领域 + +一个能装下一个小孩大小的卡通金色宝箱,外表像儿童玩具:圆鼓鼓的箱体,夸张的大锁扣,上面画着哭泣的卡通脸和小十字架。 + +在山顶小屋里的以撒房间正中央,紧贴墙角的儿童床前。 + +从外面看只是普通深度; + +实际上内部是一个**“罪的囚室”**——像游戏里的地下层一样无尽向下延伸,墙上贴满儿童画、忏悔纸条和撕碎的家庭照片。 + +被拖入宝箱内部的人,会在这里反复经历“被指责、被抛弃、被称为罪的根源”的记忆(有自己的,也有以撒的)。 + +**开启条件:** + +- 在以撒房间里,有人: + - 大声说出“都是我的错”, + - 或者指着别人说“都是你的错”; +- 或对着宝箱**流泪 / 忏悔 / 自残**(可以只提“伤害自己”,具体由pl演出,不用写方法)。 + + + +- **效应:** + - 房间门自动上锁,外面声音变得模糊; + - 宝箱在地上拉出一圈“泪水形状”的水渍,形成领域边界; + + + + + +## 冲动 + +> **把一切“罪”收纳进自己,直到世界上只剩下“我这个罪人”。** + +触发行为: + +- 当特工/居民 **把错误推给别人** —— + “都是你的错,是你害的。” +- 或者当某个人说: + “是我的错...” + +异常体会立刻察觉并尝试: + +1. 把那段“罪”刻进目标记忆,让目标逐渐**相信自己就是所有事情的源头**; +2. 若目标抵抗,宝箱会尝试**改写周围人的记忆**,让所有人开始一起指责他。 + +## 外形 + +从远处看,它只是一个**金黄色的卡通宝箱**,静静待在原地。但靠近时,会逐渐显露出“活物”的特征: + +- 箱盖内侧有两道水渍,像是**倒挂的眼睛**,偶尔会眨动; + +- 箱身表面的卡通图案会缓慢变形,变成以撒的脸、母亲的脸、特工熟人的脸,嘴巴不断重复一句: + + > “都是你的错。” + + ![image-20251120225604227](F:\记录\三角机构\image-20251120225604227.png) + +1. + +## 可选任务 + +**+1 嘉奖**:向陷入自责的人真诚伸出援手(现实的、有效的,而非敷衍安慰)。 + +**+3 嘉奖**:成功让至少一个 NPC 意识到“这不是他的错”,从自我憎恨中走出来。 + +**+1 申诫**:进行一场有实际赌注的赌博行为(包括赌场、暗箱操作、用生命/他人安全做赌注)。 + +## 当前状况 + +以撒生活在山顶上的小房子里,与父母相依为命。然而父母关系破裂,父亲经常争吵并偷窃家里财物,最终离家出走。母亲因失去丈夫和家庭暴力而精神失常,沉迷于基督教电视节目和毒品,她听到“来自上天的声音”认为以撒被罪恶腐蚀,于是夺走他的所有玩具和衣物并将他锁在房间中。 + +刚开始以撒只是觉得罪在自己于是把自己封闭在房间里面哭泣 + +结局岔路: + +- **善终线**: + + - 特工设法说服(或抱着)以撒,告诉他:错的不是他,而是这个世界(bushi) + - 若特工只是在逻辑层面推理,而**没有任何人真正试图安放以撒的罪与痛** 以撒基本无法相信 + - 回收或封印宝箱; + +- **恶化线**: + + - 以撒完全被“罪我”吞噬,成为堕落以撒; + + - 宝箱转移领域,跟着堕落以撒去到别的城市,模组结局写一句: + + > “以撒只是第一个。他不会是最后一个。” + +## 母亲的忏悔书 + +抱歉以撒,我的孩子,我十分爱你。但是我听到了上帝的呼唤,抱歉孩子,我要向上帝证明我爱他胜过爱你。我听见那声音从电视机里钻出来,它说你被罪恶腐蚀,需要被拯救。我锁起房门,是想保护你不再受到外面恶魔的诱惑。 + +可是那些yao-,那些让我暂时忘记痛苦的--,让我看到更多的幻影。我看见天使挥舞火焰的剑,也看见恶魔藏在你的笑容里。我知道这是试炼,是上帝在考验我是否愿意献出最爱的人来证明对他的信仰。 + +我曾经握着刀站在你的小床旁,泪水滴在你的额头。我祈祷xx,但xx和祷告交织在一起,变成了低语与幻觉。 + +如今,我的手一直在颤抖,心里却有一种奇异的平静。也许这是上帝赐予的慈悲,也许只是那些药物让我麻木。我写下这些话,只是想让你知道,无论我做了什么,我都带着母亲的爱。正是因为这爱,我才相信把你奉献给主是唯一的救赎。 + +主爱世人,我爱你(你被划掉),我爱主!!! + +## 学校的墙 + +1.走廊那面墙并不像是普通的“宣传板”,更像是一块被孩子和恶意一起撕扯过的皮肤。蜡笔、粉笔、圆珠笔全都糊在上面,层层叠叠,最后只剩下同一种东西——以撒被欺负的画面。 + +这些绘画看上去并不是一次画成的,而是被反复涂改、覆盖。某一张图上,以撒原本只是在桌子边掉眼泪,但后来有人又用黑笔把他的影子拉得很长,拉到整个教室中央,(好像他成了所有不幸的“根源” 不用跟特工说出来);另一幅里,他的脸被重新画了好几层,最后模糊成一个没有五官的肉团,只剩下大颗的蓝色泪点滴落。 + 红色、黑色、深蓝色反复交错,有的地方纸已经被磨破,露出后面的水泥墙皮。远远看去,这些画连成一整片阴影,像是一群孩子把所有对以撒的恶意一层层钉死在墙上,生怕有一天他会从墙里爬出来,把这些记忆拿走。 + +2.以撒曾经获得过一个女孩的苹果,但是当他吃下去的时候,发现里面有一个剃刀....他的嘴被划破了 + + + +## 赌场赌徒 + +特工刚靠近吧台,就听见旁边几个人在大笑。一个秃顶的老赌徒晃着杯子,眼皮半垂,醉意上头,话却越来越放肆: + +> “你们还记得那个……叫什么来着?哦,对,那个整天抱着圣经的疯女人的老公。” +> “就是那个小鬼他爸,长得瘦瘦的,总爱穿一件旧西装。啧,那家伙可真会赌。” + +另一个赌徒哼了一声,把筹码往桌上一推: + +> “会赌?他那叫偷命来赌。每次来这儿都说什么‘最后一把’,结果第二天又蹿回来。你们没看见啊,他掏钱那眼神,比我们都急。” + +秃顶的老赌徒凑近,压低了声音,像是在说一个好笑又理所当然的秘闻: + +> “他哪来的钱?家里那个疯女人哪舍得给? +> 他就从家里偷——先是老婆钱包里的现金,后来连家里储蓄罐都砸了。 +> 我还亲眼看见过一次,他拿着一个小孩的存钱罐来换筹码,里面全是硬币,叮当一倒,全是血汗呢。” + +旁边有人跟着笑: + +> “小鬼的血汗钱呗。那小鬼叫什么?以撒? +> 听说他妈发现钱不见了,就更疯了——成天嚷嚷什么‘罪’啊‘试炼’啊。哈哈,这种家里出来的问题孩子,迟早出事。” + +老赌徒抖了抖烟灰,似乎还想再补一刀: + +> “别这么说,他爸也可怜啊。 +> 在家天天吵架,女人整天对着电视祷告,他就只能来这儿。 +> 偷点钱,赌两把,输光了再偷。啧,这个镇子不就这样? +> 谁没有点见不得光的小动作?” + +说到这儿,几个人又齐声大笑,把“偷家里钱来赌博”当成再普通不过的笑谈。 + 在他们嘴里,以撒的父亲不是什么“罪人”,只是个“赌狠了点的普通男人”;而被偷走的,是一个家庭最后一点摇摇欲坠的安全感,是一个孩子本该属于自己的、唯一的存钱罐。 + + + +## 补充 + +作者的话:这个异常体基本就是按照游戏《以撒的结合》游戏背景故事写的 + +各位经理们可以根据我下面的背景介绍增加内容 + +**母亲被宗教和毒品洗脑 → 上帝的声音 → 献祭儿子;** + +**父亲赌博、逃避、失职 → 赌场线索;** + +**学校欺凌 → 墙上的画、苹果和剃刀;** + +**以撒把一切罪归到自己身上 → 宝箱、罪的领域、‘我就是罪’的焦点。** + + + + + +### 一、开端设定:山顶小屋与“上帝的声音” + +- 以撒(Isaac)和母亲住在山顶的一间小房子里。 + - 以撒在房间里画画、玩玩具; + - 母亲整天看电视上的基督教节目,是那种非常虔诚、但也有点偏执的信徒。 +- 某一天,母亲听到“来自上天的声音”,她相信那就是上帝: + 1. 第一次,声音说:**“你的孩子被罪恶腐蚀,需要被拯救。”** + 她于是把以撒的玩具、画本、甚至衣服都拿走,说要“除去罪恶”。 + 2. 第二次,声音说:**要让他与世上所有邪恶隔绝。** + 母亲于是把以撒锁在房间里,不让他见任何人。 + 3. 第三次,声音说:**她做得很好,但为了证明信仰,还必须献祭自己的孩子。** + 母亲拿起厨房里的大刀,准备去杀掉以撒,以示对“上帝”的绝对忠诚。 +- 以撒透过房门缝看到母亲拿刀走来,惊恐之下,在地毯下发现一扇隐藏的活板门,于是跳进地下室——**游戏就从这里正式开始**: + 每一条新路线(新一局游戏)都可以理解为:以撒再次跳下去后,在地下世界展开的另一次尝试。 + +------ + +### 二、地下旅程:一层层接近“母亲” + +游戏是类 Roguelike 的结构,但从**故事线**来看,可以粗分为几大阶段: + +- 在经典路线中,中后期的关键 Boss 是: + - **Mom(妈腿)**:一条巨大的女性腿不断从天花板砸下。 + - 更深处是 **Mom’s Heart / It Lives**(母亲的心脏 / 它活着),象征他杀死或试图“超越”母亲控制。 +- 打败 Mom 后,以撒继续往更不可理解的空间前进。 + +1. **后期路线:天堂、地狱、教堂、黑暗房间** + 随着解锁和 DLC,故事分支越来越多: + - **Sheol / The Cathedral** + - 走“地狱”线会与 Satan 战斗; + - 走“教堂”线则会上到 Cathedral,与“Isaac / ???”之类的自我形象战斗。 + - **The Chest / Dark Room** + - 进一步的隐藏关卡:“宝箱”和“黑暗房间”,Boss 变为 **The Lamb** 等,暗示更深层的罪与救赎意象。 + - 最终在 Repentance 路线中,还加入了另外一条极长的分支,更直接地触及“父母、家庭破裂与自我毁灭”的主题。 + +------ + +### 三、多结局结构:碎片化的记忆与暗示 + +原版 + 扩展 + 重制版里有非常多结局动画 + +- 前面很多结局只是**解锁道具、角色或新机制的引导**; +- 真正与剧情有关的结局,会反复出现这些元素: + - 家庭合照、以撒的房间、宝箱、画本; + - 以撒蜷缩在角落里哭泣的样子; + - 母亲的阴影,父亲离开的身影; + - 以撒画出的另一个“自己”(蓝宝宝、罪我等)。 + +这些结局并没有给出一个“官方唯一答案”,而是故意留白,让玩家自己去拼。 + +------ + +### 四、故事常见解读(官方留白 + 玩家推测) + +因为作者 Edmund McMillen 本人也说过,他想用这个游戏去谈自己对宗教和家庭的感受,而不是给一个标准答案,所以社区里有几个主流解读: + +1. **现实世界 + 脑内幻想混合说** + + - 开头那段“母亲听到上帝的声音”多半是真实的——她是因为宗教狂热 + 精神问题,真的想杀孩子; + - 以撒跳进地下室后发生的一切,更像是他**在恐惧、濒死或长期虐待中构建的幻想世界**: + - 怪物 = 他眼中的大人、同学和自己的身体; + - Boss = 对母亲、对自己罪恶感的具象化。 + +2. **宝箱窒息 / 自我封闭说** + + - 部分结局暗示:以撒可能躲进一个箱子或衣柜,把自己关起来,最后在里面死去; + - 游戏过程 = 他临死前不断重播的记忆与幻想,或者是他用来合理化自己遭遇的一套“地狱冒险”剧情。 + +3. **家庭破裂与父亲的缺席** + + - 后续资料和访谈都提到:父亲离家与酒精、金钱有关,家里的争吵、贫穷和暴力,构成了以撒的童年背景。 + + - 游戏中的爸爸道具、家庭合照撕裂等画面,都是在不断提醒: + + > 这个孩子并不是只被“宗教母亲”伤害,而是被整个破碎家庭一起推向绝境。 + +4. **主题:宗教恐惧 + 自我厌恶 + “原罪感”** + + - 游戏的关键不是讲一个线性的“从 A 到 B 的故事”,而是让你反复处在: + - “我是不是天生就有问题?” + - “大人说我是罪的来源,那我是不是干脆变成怪物算了?” + - 所有道具名字、敌人形象、Boss 设计都围绕“七宗罪”“忏悔”“献祭”“母体”和“胎儿”的意向不断循环,强化这种压抑感。 \ No newline at end of file diff --git a/三角机构/战报模板.pptx b/三角机构/战报模板.pptx new file mode 100644 index 0000000..71cffd4 Binary files /dev/null and b/三角机构/战报模板.pptx differ diff --git a/三角机构/永恒之泉.md b/三角机构/永恒之泉.md new file mode 100644 index 0000000..e24f83e --- /dev/null +++ b/三角机构/永恒之泉.md @@ -0,0 +1,54 @@ + + +位于三联城市中心的奢华医疗水疗中心“源泉”,最近推出了一款名为“奥可菲”的新系列产品—— 一套高效且广受欢迎的抗衰老护肤品。这些产品带有一系列不寻常的副作用:灵魂出窍体验、闪回从 未发生过的事件、一阵阵无法抗拒的忧郁…——而这仅仅是个开始。原因是:这些产品由一种被囚禁 在“源泉”地底深处的异常体的提取精华制成。如果任其发展,这个植物形态的异常体的影响力将在 城市中扩散,引诱越来越多的人在它迅速扩张的领域中走向死亡。 + + + +## 历史 + +​ 这种异常体以某种形式存在了数百年,稳定地以 人类阻止时间无情脚步的欲望为食。它诞生于 16世纪初,源于胡安·庞塞·德莱昂在今日佛 罗里达的丛林中寻找青春之泉的传说。那些探险 家实际上找到了一个拥有他们所寻求力量的异常 体–——但他们对此一无所知。他们烧毁了它和 它的森林,以建立一个定居点。这个异常体的第 一次生命以悲剧、记忆的丧失和家园的毁灭而告 终。 + +​ 它进入了休眠状态,但并未死亡。人类从未停止 对逝去时光的渴望,所以它的焦点使其在死亡边 缘得以保存。随着社交媒体的出现,以及人们对 衰老的恐惧日益绝望,这个异常体再次开始茁壮 成长–——这一次,它从其森林旧址的人行道裂 缝中发芽。 + +​ 三年前,关于在佛罗里达一个停车场发现一种奇 怪新植物的传闻,传到了源泉的财务与分销总监 Olive Huynh(她/她的)耳中。她不是个会放过 潜在商机的人,便利用自己的人脉关系网取得了 这株植物,并将其带到三联城,用于新产品的开 发。她派出了值得信赖的朋友,也是源泉的水疗 协调员Serena Evermore(她/她的),亲自去 取回这株植物。 当Serena进入那个被藤蔓扼住、异常体安家于 此的停车场时,她便知道这不是一株普通的植物。当一根好奇的卷须缠绕上她的手指时,她理解了它,它也理解了她。她感受到了它的悲伤, 它对祖居之地的渴望,并与之感同身受。她也同 样在寻找自己的根。异常体感觉它认识她。但它 想不起来为什么 + +异常体相信Serena能帮它记起过去,便自愿来 到了源泉。在这里,开发团队为它搭建了一个特 殊的围场,供其茁壮成长。多年来,他们研究出 一种可持续的方法,将其汁液、果实和叶片蒸馏 成一种具有强大焕活功效的强效产品–——但在 为它寻找新家方面却毫无进展。 现在,它变得焦躁不安。Serena没有遵守为它 寻找家园的承诺。经过多年的等待,异常体准备 采取行动了。 + + + +## 焦点 + +人类想要回到某个–或某个自我–的欲望,而那时 光或自我已然无法挽回地失去了。 + + + +## 领域 + +在三联城下方的下水道系统中萌发的一片雨林———这是对异常体最初诞生地的一份复制品,在那之后,一群16世纪的探险家将其烧为平地。 + + + +## 外观 + +异常体表现为一株西番莲藤,目前缠绕在源泉一 个玻璃笼内的棚架上。它会长出圆形光滑的果 实、宽大的紫色花朵,偶尔还会长出含泪不眨的 眼睛。它的捕捉者们不知道的是,这只是异常体 的一部分。几个月前,它在灌溉系统中发现了一 个微小的开口,并将一根匍匐茎延伸至下水道, 在那里建立了它的领域 + + + +## 冲动 + +在三联城地下的下水道系统中完全重建它的家 园。如果置之不理,这片地下丛林将延伸至城市 的供水系统,将其卷须植入所有三联城居民体 内。当它积蓄了足够的力量,它将把他们的身体 弯折到断裂点,在一场花与藤蔓的爆炸性展现中 将人们撕裂–——这股生长浪潮将把整座城市变 成它失落已久的家园。 + +## 当前状况 + +异常体的力量随着每个使用奥可菲产品的人而增 长。使用这些产品会让异常体在他们的思想中扎根,扭曲他们的记忆,并以他们的欲望为食。其影响集中在商业大道周围,那里是源泉及其主要店面的所在地。在异常体的控制下,一整片雨林 已经在大道下方的下水道中生长起来。 + + + + + +## 晨会 + +- 一名特工的伴侣兴奋地分享了他们期待已久 的水疗日计划。 +- 一名特工突然收到了来自遥远过去一位重要 人物的联络。 +- 演员Jay Hsieh似乎无处不在———电视广 告、社交媒体、广告牌、杂志———为他与 源泉奥可菲的合作大肆宣传。 +- 一群年轻人走过,他们似乎都长着同一张 脸。 \ No newline at end of file diff --git a/三角机构/特工表.pdf b/三角机构/特工表.pdf new file mode 100644 index 0000000..d9a87ce Binary files /dev/null and b/三角机构/特工表.pdf differ diff --git a/三角机构/行动审查/三角时报永恒之泉.pptx b/三角机构/行动审查/三角时报永恒之泉.pptx new file mode 100644 index 0000000..73ca02e Binary files /dev/null and b/三角机构/行动审查/三角时报永恒之泉.pptx differ diff --git a/三角机构/规则书/三角机构/三角机构-Triangle Agency-核心规则书-V1.0-V11.12.pdf b/三角机构/规则书/三角机构/三角机构-Triangle Agency-核心规则书-V1.0-V11.12.pdf new file mode 100644 index 0000000..a30e6c0 Binary files /dev/null and b/三角机构/规则书/三角机构/三角机构-Triangle Agency-核心规则书-V1.0-V11.12.pdf differ diff --git a/三角机构/规则书/三角机构/三角机构-收容库The Vault 9-15-25-v11.12.pdf b/三角机构/规则书/三角机构/三角机构-收容库The Vault 9-15-25-v11.12.pdf new file mode 100644 index 0000000..6c35818 Binary files /dev/null and b/三角机构/规则书/三角机构/三角机构-收容库The Vault 9-15-25-v11.12.pdf differ diff --git a/三角机构/规则书/三角机构/三角议程Triangle Agenda Interior .pdf b/三角机构/规则书/三角机构/三角议程Triangle Agenda Interior .pdf new file mode 100644 index 0000000..3d9b128 Binary files /dev/null and b/三角机构/规则书/三角机构/三角议程Triangle Agenda Interior .pdf differ diff --git a/三角机构/规则书/三角机构标准报告表 中译鸦版.pdf b/三角机构/规则书/三角机构标准报告表 中译鸦版.pdf new file mode 100644 index 0000000..b04fd80 Binary files /dev/null and b/三角机构/规则书/三角机构标准报告表 中译鸦版.pdf differ diff --git a/三角机构/规则书/三角议程.pdf b/三角机构/规则书/三角议程.pdf new file mode 100644 index 0000000..af96192 Binary files /dev/null and b/三角机构/规则书/三角议程.pdf differ diff --git a/三角机构/规则书/公司补给.pdf b/三角机构/规则书/公司补给.pdf new file mode 100644 index 0000000..7f63ecb Binary files /dev/null and b/三角机构/规则书/公司补给.pdf differ diff --git a/三角机构/规则书/收容库.pdf b/三角机构/规则书/收容库.pdf new file mode 100644 index 0000000..6d942cf Binary files /dev/null and b/三角机构/规则书/收容库.pdf differ diff --git a/三角机构/规则书/核心规则书.pdf b/三角机构/规则书/核心规则书.pdf new file mode 100644 index 0000000..0a3598c Binary files /dev/null and b/三角机构/规则书/核心规则书.pdf differ diff --git a/三角机构/规则书/模组表/路霸.pdf b/三角机构/规则书/模组表/路霸.pdf new file mode 100644 index 0000000..8ab233a Binary files /dev/null and b/三角机构/规则书/模组表/路霸.pdf differ diff --git a/三角机构/规则书/模组表/路霸.ppt b/三角机构/规则书/模组表/路霸.ppt new file mode 100644 index 0000000..fd3edbd Binary files /dev/null and b/三角机构/规则书/模组表/路霸.ppt differ diff --git a/三角机构/角色卡/“双叶”塞斯和艾拉.xlsx b/三角机构/角色卡/“双叶”塞斯和艾拉.xlsx new file mode 100644 index 0000000..114c022 Binary files /dev/null and b/三角机构/角色卡/“双叶”塞斯和艾拉.xlsx differ diff --git a/三角机构/角色卡/三角机构.大卫'戴.xlsx b/三角机构/角色卡/三角机构.大卫'戴.xlsx new file mode 100644 index 0000000..9ac5e4d Binary files /dev/null and b/三角机构/角色卡/三角机构.大卫'戴.xlsx differ diff --git a/三角机构/角色卡/凯恩.xlsx b/三角机构/角色卡/凯恩.xlsx new file mode 100644 index 0000000..8c2e08c Binary files /dev/null and b/三角机构/角色卡/凯恩.xlsx differ diff --git a/三角机构/角色卡/李斯·孙卿.xlsx b/三角机构/角色卡/李斯·孙卿.xlsx new file mode 100644 index 0000000..8a8c6e9 Binary files /dev/null and b/三角机构/角色卡/李斯·孙卿.xlsx differ diff --git a/三角机构/角色卡/琳达梅尔.xlsx b/三角机构/角色卡/琳达梅尔.xlsx new file mode 100644 index 0000000..da8a537 Binary files /dev/null and b/三角机构/角色卡/琳达梅尔.xlsx differ diff --git a/三角机构/角色卡/瑞克·戴克.xlsx b/三角机构/角色卡/瑞克·戴克.xlsx new file mode 100644 index 0000000..6458047 Binary files /dev/null and b/三角机构/角色卡/瑞克·戴克.xlsx differ diff --git a/三角机构/角色卡/里昂(汲取 海王 CEO).xlsx b/三角机构/角色卡/里昂(汲取 海王 CEO).xlsx new file mode 100644 index 0000000..219a9bb Binary files /dev/null and b/三角机构/角色卡/里昂(汲取 海王 CEO).xlsx differ diff --git a/三角机构/路霸.md b/三角机构/路霸.md new file mode 100644 index 0000000..a3de219 --- /dev/null +++ b/三角机构/路霸.md @@ -0,0 +1,226 @@ +# 路霸 + +## 异常体档案 + +三联城臭名昭著的拥堵地段——胜利环岛,启用了一套全新的交通控制系统:路霸,一个由传感器塔 和配套应用组成的系统,取代了该社区传统的停车标志和交通信号灯。公众并不知道,这套系统完全 由一个与被囚禁的共鸣者韦恩结合的异常体所控制。韦恩被三角机构的经济对 手、跨国科技集团米洛斯工业捕获,并被囚禁在路霸塔内。 韦恩的异常体受命于自动化三联城的早晚高峰交通,却发现自己对此毫无准备,于是它采取了一种可 怕的捷径:将有问题的司机传送到数百米的高空,关入封闭的“循环域”中,这样他们就再也不会堵 塞三联城的道路了。 + + + + + +## 历史 + +米洛斯工业在员工中发现了一名拥有缺位能力的共鸣者,而机构对此毫不知情。此人若无干预, 将会变成一个异常体。米洛斯预测异常体的最终 形态将取决于安德鲁转变时的心智状态,于是他 们使用实验性疗法,确保异常体的焦点会变成 “让交通消失”。当他的转变进展到足够程度 时,他们便将安德鲁安置在了路霸收容单元中。 米洛斯首席执行官埃里克·莫纳汉(他/他的) 与州长戴安娜·阿尔瓦雷斯(她/她的)达成协 议,在三联城以交通拥堵闻名的商业区部署路霸 交通管理系统,尽管公众抗议称基于智能手机的 系统具有排他性,且容易出故障。州长急于赢得 受交通影响最严重的郊区选民的支持,而莫纳汉 则急于挑战三角机构对三联城的经济扼制,该项 目因此进展迅速。 沟通不畅和对如何参与的普遍误解,已使该地区 的交通状况更加恶化。过去几天对司机们来说简 直是一场噩梦:没有信号灯或标志,那些无法辨 别应用通常含糊不清指令的人,被迫卷入一场万 人的胆小鬼博弈。异常体本身也加剧了混乱:在 某些情况下,司机被指示穿过人行道和建筑大 堂 + + + + + +## 焦点 + +米洛斯团队已成功将异常体的焦点转变为“让交 通消失”,这也是米洛斯用于推广这项新服务的营销口号。该营销活动以一只名为路霸的酷炫卡通猪为主角,动画广告中描绘了他 借助巨大的鼻子和獠牙,理顺拥堵的交通。 + + + +## 领域 + +`安德鲁`的异常体在路霸传感器塔周围的交叉路口,以及任何运行着路霸应用的智能手机十英尺范围内施加其影响 + + + + + +## 外观 + +路霸传感器塔外观为一个巨大的、珍珠白色的雪 茄形塔,顶部有一个绽放的蘑菇状顶盖。其顶盖 为纯黑色,覆盖着闪亮的塑料,给人一种巨型安 保摄像头的印象。无数电缆和电线将其连接到交 叉路口周围的一系列信号中继器和支撑梁上。 塔内是异常体的真实形态:安德鲁·韦恩,悬浮 在液体中,其下半身处于异常转变的晚期阶段。 血肉丝带正在分裂,化为石头,并弯曲着与自身 相连———他的整个下半身正在变成一团盘结的 道路和闪烁的交通灯 + +如果异常体完全占据了安德鲁的人格,它将重塑 他的血肉,呈现为一个由石头和三色光构成的优 雅形象,介于天使与石像鬼之间。它有着安德鲁 的脸,但长着猪的鼻子和獠牙。 + + + +## 冲动 + +由于交通已成为紧急状况,异常体“让交通消 失”的方法变得简单粗暴:它将任何它认为麻烦 的通勤者送入循环域——悬浮在城市上空数百米 的私人空间。任务开始时,路霸将任何试图进入市中心车流的新旅客都视为麻烦。 + + + + + +## 当前状况 + +路霸系统启用的头两天堪称一场灾难:市中心交 通完全瘫痪。今天,几位重要人物在前往宣布路 霸系统成功的新闻发布会途中失踪。警方已切断 了进入整个市中心商业区的新车流,这使得司机 们转而使用小路,交通状况因此更加恶化。司机 们成群结队地弃车而去,选择步行或乘坐地铁穿 城而过。 而且,尽管凡俗之人无法看见,但悬浮在城市上 空的循环域数量正在稳步增长,数十个漂浮的石 球在天空中留下斑斑点点。 + + + + + +## 晨会 + + 一名特工的智能手机接到一个电话,但直到 下载了该市强制要求的路霸应用后才能接 听。 + +X 特工们注意到城市上空悬浮着一些奇怪的形状,但他们的凡俗关系人却看不到。 + +X 一名罢工纠察线上的工人,正在用智能手机 自拍时突然消失。 + +X 一位困惑的通勤者打断了一名特工的晨间日常,因为路霸应用指示她在上班途中穿过特工的家 + + + + + +## 可选任务 + ++3 嘉奖:每当你从米洛斯工业夺走任何东西时时。 + + +1 嘉奖,每当你加固城市基础设施 + ++1 申诫,每当你坠落超过10英尺时 + + + + + +## 任务简报 + +在市中心及胜利环岛周边,已侦测到异常活动急剧增加。该街区也正处于持续交通危机的中 心,而随着机构的经济竞争对手——米洛斯工业——安装了基于应用的路霸交通管理系统,情 况已急剧恶化。机构还获悉,三联城天际线上方漂浮着巨大的神秘球体。 机构怀疑,要么是司机们的集体挫败感,要么是围绕米洛斯新应用的华丽营销活动,已累积了 足够的关注度从而创造出了一个异常体,并且这个异常体正是造成交通拥堵和这些巨大漂浮球 体的罪魁祸首。 特工们必须查明异常活动的来源和这些球体的性质,同时阻止恐慌在城市中进一步蔓延。灾难 响应小组正聚集在胜利环岛外,交通部即将在此召开新闻发布会。机构建议特工们从那里开始 调查。 为协助捕获该异常体,机构还为特工们提供了一份免费的特殊申领物:高速公路,任务完成后 须归还 + + + +## 循环域与混沌 + +每当特工进入一个循环域时,混沌池中就会增加 十点混沌,这些混沌只能在该循环域内使用。 + + + + + +# 商业区 + +## 警方路障 + +三频道新闻的记者***`唐娜`***正向紧张的警察和愤怒的通勤者连 珠炮般地提问。她独自工作,用一台面部追踪无人机拍摄自己 + + + +### 特工们可以通过回答唐娜的几个问题了解 到以下信息: + +州长的整个车队都消失了,包括州长***`戴安娜`***和副州长***`亚伦`***,这可能导致一场继任危机。 + +自交通噩梦开始以来,米洛斯首席执行官 ***`埃里克***·莫纳汉`就再也没有露面。有传言 称,在路霸灾难性的发布后,他已经躲了起来。 + + + +## 新闻发布会 + +这场原为州长庆祝路霸系统成功而举办的新闻发 布会,现在成了一个灾难响应区。当特工们抵达 时,还没有人走上讲台;***三联城市长***里***`史密斯`*** 和***米洛斯公关副总裁***`莫 妮卡` 正在后台争论该向媒 体发布何种说辞: 史密斯市长认为,是时候宣布进入紧急状态,并立即暂停路霸项目,必要时强制卸载。 + +莫妮卡不知道路霸及其内部异常体的真实性质, 但她明白,任何意外的干扰———尤其是军事响 应———都可能激怒路霸并产生意想不到的后 果。她主张给米洛斯的团队更多时间来找出解决 问题的办法 + + + +## 后台 + +`埃里克·莫纳汉`的行政助理`卡梅伦`· 也在后台。他一手拿着一个米洛斯专有平板电脑,另一只手在笔记本电脑上打字。 卡梅伦非常看重米洛斯与机构之间的竞争关系, 对任何与三角机构有关的人都抱有公开的敌意。 如果他得知特工们的真实身份,他会打断任何对 话,指示附近的米洛斯安保人员将特工们护送得 越远越好。 + + + +### 特工们可以通过偷走卡梅伦的设备或使用 异常手段了解到以下信息: + +- `米洛斯`,或者至少是`卡梅伦`,知道异常体 的存在–——平板电脑上显示着一个交叉路口的摄像头画面,该画面模拟了“生长” 系能力“眼睛”的异常体追踪效果。 +- 通过这个视角,特工们可以看到路霸内部 安德鲁的轮廓,他的身体已经处于变形中期。 +- 米洛斯曾试图用一个凡俗的“紧急关闭开 关”来中和路霸,但没有成功———他们 确信该异常体曾是一个活物,但现在已不 再是了。 +- 一个被派去“手动禁用”路霸的质量控制小组已经失踪。 + + + +## 胜利环岛 + +溜过警方警戒线的特工可以步行接近胜利环岛的 中心交叉口。当他们穿过商业区,经由狭窄且交 叉路口频繁的街道前往胜利环岛时,会发现该市 已拆除了所有的交通信号灯和标志,代之以路霸的传感器塔和信号中继器。 + + + +如果任何特工在进入胜利环岛本体时手机上安装 了路霸应用,他们以及任何同行者都会被异常体 传送进一个循环域。 + +如果没有特工安装该应用,或把智能手机留下 了,异常体就会等到他们靠近一辆车里有安装该 应用的人时,将他们和那辆车一起传送走。 否则,如果特工们物理上足够靠近,能被异常体 侦测到其存在,它就会立即将他们送入一个循环 域。 + + + + + +## 市长的循环域 + +州长阿尔瓦雷斯的循环域呈现为一艘外观朴素的船屋(名为“海上核心小组”)及其周围位于三联城 富人区阿什福德的码头。无论是通过“高速公路”还是被“路霸”传送,特工们都会抵达这个循环域 中停泊船只的码头尽头 + + + +码头 这个私人码头是三联城一些最富有、最有权势的 居民的停泊处。当特工们抵达时,唯一能看到的 人是州长的三名随行人员,他们正站着争吵。 + +- `布拉德·克雷默`中尉(他/他的)已前往最近的 警察分局请求支援,并查明他们的无线电为何失 灵。几分钟后,他会气喘吁吁地回来,因为他在 几个街区外偶然撞见了循环域的边缘。如果让他 汇报情况,他会将整个团队变成散逸端。 +- 新闻秘书`米奇·罗兹`(他/他的)不希望这次访 问留下任何记录。他正试图让同伴们保持安静和 谨慎,但并未成功。 +- 副州长`亚伦·李`(他/他的)想要哗变,架空州 长,并直接干预交通问题。他坚信是米洛斯首席 执行官埃里克·莫纳汉故意制造了交通拥堵,并 打算找到他并威胁他,以制止此事。 +- ``凯伦·梅森``警官(她/他们的)阻止李副州长登 船。她希望所有人都留在原地,直到布拉德·克 雷默中尉带着更多信息和支援回来。 + + + +1. 如果特工们询问州长的下落,米奇会站出来 回避问题,并告知特工们州长的日程表可以在网 上查到(实际上查不到) +2. 如果特工们能说服随行人员,让他们相信自己有 事要找阿尔瓦雷斯州长,米奇会按响码头上的门 铃,戴安娜会在船的甲板上接待特工们。如果她 觉得他们值得一谈,就会邀请他们进去。 + + + +## 海上核心小组 + +州长船只低调的外观掩盖了其奢华而精心制作的 内饰。巨大的有色玻璃窗提供了环绕式的水景, 而船尾附近的一座硬木吧台与一排别致、看起来 很舒适的椅子相对而立。 + +如果特工们不请自入,她正对着电话大喊: + + “安全词为什么没用?安德鲁·布伦特!安德鲁· 布伦特!安德鲁·布伦特!没用!” + + 在激动之下,她记错了安德鲁·韦恩的名字。当 以“安德鲁·布伦特”为目标时,“高速公路” 毫无反应。电话那头其实并没有人,但如果特工 们检查,可以发现她当时正试图联系`英迪拉·罗 伊`。 + + + +## 埃里克·莫纳汉 + +埃里克的循环域呈现为他在三联城市中心胜利广场一号米洛斯总部的顶层办公室。高速公路会将特工 们直接送到他私人办公室外的等候室 + + + +### 等候室 + + + + + +# 角色卡 + +> 塞斯和艾拉 + +目录 + +海王 + +实习生 + +>李斯·孙卿 + +目录 + +顶梁柱 + +前台 + +> 里昂.威廉姆斯 + +汲取 + +海王 + +CEO + +> 大卫戴 + +低语 + +异类 + +PR \ No newline at end of file diff --git a/山东理工大学/408/离散数学.md b/山东理工大学/408/离散数学.md new file mode 100644 index 0000000..e934945 --- /dev/null +++ b/山东理工大学/408/离散数学.md @@ -0,0 +1,67 @@ +# SDUT-离散数学-2024-计科2306(恩师王举辉) + +此计不成,既有后来人。 + +欢迎sduter来进行讨论与指正。 + +# 感悟 + +这门课程就是为了后面的数据结构后学习的 主要还是以定义以及性质定理为主, 就是上课好好听(bushi)然后刚开始听可能不懂,但是后来回过头看一看 欸 突然开窍了。嘿嘿嘿。 + +题目不是很难 但是就是定义以及性质的运用 + +# 章一 + +![1](C:\Users\33882\Desktop\离散数学\1.jpg) + +![2](C:\Users\33882\Desktop\离散数学\2.jpg) + +# 章二:谓词逻辑&章三:集合与关系 + +![3](C:\Users\33882\Desktop\离散数学\3.jpg) + +![4](C:\Users\33882\Desktop\离散数学\4.jpg) + +![5](C:\Users\33882\Desktop\离散数学\5.jpg) + +![6](C:\Users\33882\Desktop\离散数学\6.jpg) + +![8](C:\Users\33882\Desktop\离散数学\8.jpg) + +# 章四:函数 + +![10](C:\Users\33882\Desktop\离散数学\10.jpg) + +章五:代数系统 + +![11](C:\Users\33882\Desktop\离散数学\11.jpg) + +![12](C:\Users\33882\Desktop\离散数学\12.jpg) + + + +![13](C:\Users\33882\Desktop\离散数学\13.jpg) + +![14](C:\Users\33882\Desktop\离散数学\14.jpg) + +# 最后一章:图论 + +![15](C:\Users\33882\Desktop\离散数学\15.jpg) + +![16](C:\Users\33882\Desktop\离散数学\16.jpg) + +![17](C:\Users\33882\Desktop\离散数学\17.jpg) + +![18](C:\Users\33882\Desktop\离散数学\18.jpg) + +![19](C:\Users\33882\Desktop\离散数学\19.jpg) + +![20](C:\Users\33882\Desktop\离散数学\20.jpg) + +![21](C:\Users\33882\Desktop\离散数学\21.jpg) + +![22](C:\Users\33882\Desktop\离散数学\22.jpg) + +![7](C:\Users\33882\Desktop\离散数学\7.jpg) + +![9](C:\Users\33882\Desktop\离散数学\9.jpg) \ No newline at end of file diff --git a/山东理工大学/408/计网.md b/山东理工大学/408/计网.md new file mode 100644 index 0000000..b65f0c6 --- /dev/null +++ b/山东理工大学/408/计网.md @@ -0,0 +1,138 @@ +# 范围 + +# 计算机网络各章节复习重点 + +## 第1章:计算机网络基础 + +- **交换方式** + - 电路交换、报文交换、分组交换的特点及适用场景。 +- **网络分类** + - 分类标准(如覆盖范围、拓扑结构等)。 +- **体系结构** + - **OSI七层模型**(理论模型)与 **TCP/IP四层模型**(实际应用)的层次划分及各层作用。 + - 五层模型(简化理解)的层次:物理层、数据链路层、网络层、运输层、应用层。 + +--- + +## 第2章:物理层 + +- **关键概念** + - 信道极限容量(奈奎斯特定理、香农公式)的含义及计算。 + - 码元、比特的区别;通过码元携带更多信息提高传输速率的方法。 +- **复用技术** + - 频分复用(FDM)、时分复用(TDM)、统计时分复用(STDM)、波分复用(WDM)的工作原理。 + - 课后练习题:涉及数据发送方、码元与比特的计算。 + +--- + +## 第3章:数据链路层 + +- **基本概念** + - 链路、数据链路的定义;三个基本问题(封装成帧、透明传输、差错检测)。 + - CRC校验码的计算(需掌握课后习题)。 +- **设备与协议** + - 适配器(网卡)的功能。 + - CSMA/CD协议的工作原理(以太网介质访问控制)。 + - 集线器(物理层)与交换机(数据链路层)的区别;交换机的自学习机制及转发表建立过程。 +- **VLAN** + - VLAN的类型(如基于端口、MAC地址等)???及优点(隔离广播域、提高安全性等)。 + +--- + +## 第4-5章:网络层 + +- **IP地址与子网划分** + - 分类IP地址(A/B/C/D/E类)的判断;无分类编址(CIDR)与子网掩码的作用。 + - 子网划分(固定长度子网、可变长子网VLSM):子网号、地址范围、可用地址的计算(需结合子网掩码)。 +- **路由选择** + - 路由器转发分组的算法:目的IP与子网掩码按位与运算得到网络号,匹配转发表(优先顺序:主机路由 → 网络路由 → 默认路由)。 + - 路由协议分类: + - 自治系统(AS)内部:RIP、OSPF等。 + - 自治系统间:BGP。 +- **特殊地址与技术** + - 专用地址(私有地址)的范围及特点(互联网路由器不转发)。 + - 虚拟专用网(VPN)与网络地址转换(NAT)的应用场景及区别。 + +--- + +## 第6章:运输层 + +- **协议对比** + - TCP与UDP的特点及区别(连接性、可靠性、传输单位等)。 + - 端口号的作用:区分不同应用进程。 +- **TCP核心机制** + - 滑动窗口机制:发送窗口大小由接收窗口和拥塞窗口共同决定。 + - 流量控制与拥塞控制的实现:调整窗口大小;拥塞控制算法(慢开始、拥塞避免、快重传、快恢复)。 + - 三次握手建立连接、四次挥手释放连接的过程及原因。 +- **UDP特点** + - 无连接、不可靠、面向报文,适用于实时数据传输(如视频流)。 + +--- + +## 第7章:应用层 + +- **域名系统(DNS)** + - 四类服务器(根域名服务器、顶级域名服务器、权限域名服务器、本地域名服务器)的作用及域名解析过程。 +- **万维网(WWW)** + - 解决的四个核心问题及对应技术(HTTP协议、URL、HTML等)。 +- **常见应用协议** + - 区分使用TCP(如HTTP、FTP)和UDP(如DNS、DHCP)的高层协议。 + +--- + +## 第8章:网络安全 + +- **安全威胁** + - 被动攻击(窃听、截获)与主动攻击(篡改、伪造)的区别。 +- **加密技术** + - 对称加密(如DES)与非对称加密(如RSA)的模型及应用场景。 +- **数字签名与保密** + - 数字签名的作用(鉴别发送者);结合加密实现保密的方法(如用接收方公钥加密)。 +- **安全设备** + - 防火墙的功能;入侵检测系统(IDS)的作用。 + +--- + +## 其他重点 + +- **实验与作业** + - 实验报告需手写并扫描上传;重视课后习题(子网划分、CRC计算、路由转发算法)。 + - 平时成绩构成:作业、实验、课堂表现。 +- **复习建议** + - 重点掌握PPT内容及教材指定章节(如分组转发算法见143页,TCP/UDP特点见216/219页)。 + + + +# 物理层 + +# 数据链路层 + +## CSMA/CD + +image-20250601215956519 + + ANS:B + +image-20250601220104712 + + + +![image-20250601220355280](F:\记录\image-20250601220355280.png) + + + +![image-20250601220748017](F:\记录\image-20250601220748017.png) + + + +## 交换机的自学习功能 + +![image-20250606171956311](F:\记录\image-20250606171956311.png) + + + +# 网络层 + + + +![image-20250606214847373](F:\记录\image-20250606214847373.png) \ No newline at end of file diff --git a/山东理工大学/image-20251118123812065.png b/山东理工大学/image-20251118123812065.png new file mode 100644 index 0000000..b155d6d Binary files /dev/null and b/山东理工大学/image-20251118123812065.png differ diff --git a/山东理工大学/其他/lab3.md b/山东理工大学/其他/lab3.md new file mode 100644 index 0000000..8e1f609 --- /dev/null +++ b/山东理工大学/其他/lab3.md @@ -0,0 +1,259 @@ +```sql +-- 增删改 +INSERT INTO products (maker, model, type) +VALUES ('I', '3008', 'printer'); +INSERT INTO sales (customer_id, model, quantity, day, paid, type_of_payment) +VALUES ('1112223333', '3008', 2, '2024-01-01', 200, 'cash'); +INSERT INTO customers (customer_id, firstname, lastname, city, address, email) +VALUES ('1112223333', 'Lisa', 'Smith', 'Dublin', '5 Main St.', 'lisa@example.com'); + +-- 更新 +UPDATE pcs +SET price = 2200 +WHERE model = '1001'; + + +UPDATE sales +SET type_of_payment = 'visa credit' +WHERE customer_id = '1122334455' AND model = '2010'; + +UPDATE customers +SET email = 'norah.jones@yahoo.com' +WHERE customer_id = '9999999999'; + +-- 删除 +DELETE FROM printers +WHERE model = '3006'; + + +DELETE FROM sales +WHERE day = '2013-12-17'; + +DELETE FROM customers +WHERE customer_id = '1231231231'; + + + + +-- 完成数据库新用户创建、 +CREATE USER `zds` +-- 授权访问数据库、 +GRANT SELECT, UPDATE, INSERT ON TABLE sales TO zds; + +-- 授权用户传递权限(with grant option) +GRANT SELECT ON sdut.sales TO zds WITH GRANT OPTION +-- 收回用户的sales表更新权限 +REVOKE UPDATE ON sdut.sales FROM zds; + +-- 收回所有权限(彻底回收) +REVOKE ALL PRIVILEGES ON sdut.sales FROM zds +-- 删除创建的用户 +DROP USER zds; + + + + + +-- 触发器 +-- 1 +CREATE TABLE pcprice_log ( + log_id INT AUTO_INCREMENT PRIMARY KEY, + model VARCHAR(10) NOT NULL, + old_price DECIMAL(10,2) NOT NULL, + new_price DECIMAL(10,2) NOT NULL +); + + +CREATE TRIGGER insert_pcpricelog_values_when_pc_price_changed +AFTER UPDATE ON pcs +FOR EACH ROW +BEGIN + IF OLD.price != NEW.price THEN + INSERT INTO pcprice_log (model, old_price, new_price) + VALUES (OLD.model, OLD.price, NEW.price); + END IF; +END; + +-- 测试 +-- INSERT INTO pcs (model, price, speed, ram, hd ) +-- VALUES ('1005', 200, 3.0, 8, 512); +-- UPDATE pcs set price=22 WHERE model=1005 + + +-- 2定义AFTER行级触发器,当删除顾客表Customer中的一个顾客信息后,同时删除购买信息表Sales中该顾客的所有购买记录 + +CREATE TRIGGER deleteCustomer +after DELETE on customers +for each row +BEGIN + DELETE FROM sales + WHERE customer_id = OLD.customer_id; +END + +-- -- 测试 +-- DELETE FROM customers WHERE customer_id=9999999999 + +-- 3需要对在表上进行DML操作的用户进行安全检查,看是否具有合适的特权 +-- 权限表:存储用户可执行的DML权限(JSON数组格式,如["insert","update"]) +CREATE TABLE IF NOT EXISTS userPrivilege ( + id INT PRIMARY KEY AUTO_INCREMENT, + user_name VARCHAR(100) NOT NULL UNIQUE COMMENT '用户名(格式:user@host,如root@localhost,匹配CURRENT_USER())', + privilege JSON NOT NULL COMMENT '权限列表,JSON数组,值为"insert"/"update"/"delete"(统一小写)', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '权限创建时间' +); + +-- 插入测试数据:给用户zds@localhost分配INSERT/UPDATE权限,不给DELETE权限 +INSERT INTO userPrivilege (user_name, privilege) +VALUES ('zds@localhost', '["insert", "update"]'); +-- 权限表:存储用户可执行的DML权限(JSON数组格式,如["insert","update"]) +CREATE TABLE IF NOT EXISTS userPrivilege ( + id INT PRIMARY KEY AUTO_INCREMENT, + user_name VARCHAR(100) NOT NULL UNIQUE COMMENT '用户名(格式:user@host,如root@localhost,匹配CURRENT_USER())', + privilege JSON NOT NULL COMMENT '权限列表,JSON数组,值为"insert"/"update"/"delete"(统一小写)', + create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '权限创建时间' +); + +-- 插入测试数据:给用户zds@localhost分配INSERT/UPDATE权限,不给DELETE权限 +INSERT INTO userPrivilege (user_name, privilege) +VALUES ('zds@localhost', '["insert", "update"]'); + +DELIMITER // +CREATE TRIGGER trg_check_update_priv +BEFORE UPDATE ON customers -- 同样可替换为目标表 +FOR EACH ROW +BEGIN + DECLARE user_priv JSON; + DECLARE has_update INT DEFAULT 0; + DECLARE curr_user VARCHAR(100) DEFAULT CURRENT_USER(); + + -- 查询当前用户权限 + SELECT privilege INTO user_priv + FROM userPrivilege + WHERE user_name = curr_user; + + -- 判断是否有"update"权限 + IF user_priv IS NOT NULL THEN + SET has_update = JSON_CONTAINS(user_priv, '"update"'); + END IF; + + -- 无权限抛错 + IF has_update = 0 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = CONCAT('安全检查失败:用户 [', curr_user, '] 无 ', TABLE_NAME, ' 表的 UPDATE 权限'); + END IF; +END // +DELIMITER ; +DELIMITER // +CREATE TRIGGER trg_check_delete_priv +BEFORE DELETE ON customers -- 同样可替换为目标表 +FOR EACH ROW +BEGIN + DECLARE user_priv JSON; + DECLARE has_delete INT DEFAULT 0; + DECLARE curr_user VARCHAR(100) DEFAULT CURRENT_USER(); + + -- 查询当前用户权限 + SELECT privilege INTO user_priv + FROM userPrivilege + WHERE user_name = curr_user; + + -- 判断是否有"delete"权限 + IF user_priv IS NOT NULL THEN + SET has_delete = JSON_CONTAINS(user_priv, '"delete"'); + END IF; + + -- 无权限抛错 + IF has_delete = 0 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = CONCAT('安全检查失败:用户 [', curr_user, '] 无 ', TABLE_NAME, ' 表的 DELETE 权限'); + END IF; +END // +DELIMITER ; + +-- 4如果某个特定客户ID的购买记录从销售表中删除后,则从客户表中删除该客户。 +CREATE TRIGGER deleteCustomer_by4 +AFTER DELETE on sales +for each row +BEGIN + DELETE FROM customers + WHERE customer_id = OLD.customer_id; +END + +CREATE TRIGGER discount AFTER INSERT ON sales FOR EACH ROW +BEGIN + DECLARE + sum_paid DECIMAL ( 12, 2 ); + DECLARE + discount DECIMAL ( 5, 2 ); + SELECT + sum( paid ) INTO sum_paid + FROM + sales + WHERE + customer_id = NEW.customer_id; + SELECT + discount INTO discount + FROM + customers + WHERE + customer_id = NEW.customer_id; + IF + SUM_paid > 10000 + AND discount < 10.00 THEN + UPDATE customers + SET discount = 10.00 + WHERE + customer_id = NEW.customer_id; + + END IF; + + END + + +-- 6在客户中添加一个新的"AllPaid"栏,如果插入或更新或删除一个销售元组,那么修改该客户的"AllPaid"的值 + +ALTER TABLE customers +ADD COLUMN AllPaid DECIMAL(12,2) NOT NULL DEFAULT 0.00 + +CREATE TRIGGER insert_value_customer +AFTER INSERT on customers +for each ROW +BEGIN + UPDATE customers + set AllPaid =( + SELECT SUM(paid) FROM sales + WHERE customer_id = NEW.customer_id + ) + WHERE customer_id = NEW.customer_id; + END + + + CREATE TRIGGER UPDATE_value_customer +AFTER UPDATE on customers +for each ROW +BEGIN + UPDATE customers + set AllPaid =( + SELECT SUM(paid) FROM sales + WHERE customer_id = NEW.customer_id + ) + WHERE customer_id = NEW.customer_id; + END + + + CREATE TRIGGER DELETE_value_customer +AFTER DELETE on customers +for each ROW +BEGIN + UPDATE customers + set AllPaid =( + SELECT SUM(paid) FROM sales + WHERE customer_id = old.customer_id + ) + WHERE customer_id = old.customer_id; + END +-- 测试 + + +``` + diff --git a/山东理工大学/其他/lab4.md b/山东理工大学/其他/lab4.md new file mode 100644 index 0000000..6aa8673 --- /dev/null +++ b/山东理工大学/其他/lab4.md @@ -0,0 +1,96 @@ +CREATE PROCEDURE RateModel ( IN cid VARCHAR ( 20 ), IN m VARCHAR ( 20 ), IN r INT ) BEGIN-- 1. 插入新评分记录 + INSERT INTO ratings ( customer_id, model, rating_time, rating ) + VALUES + ( cid, m, NOW( ), r ) -- 2. 更新 Products 表的总评分和评分次数 + INSERT IGNORE INTO Products ( total_rating, number_of_ratings ) + VALUES + ( 0, 0 );-- 3. 计算该型号的最新总评分和评分次数 + UPDATE products + SET total_rating = ( SELECT COALESCE( SUM( rating ), 0 ) FROM Ratings WHERE model = m ), + number_of_ratings = ( SELECT COUNT( * ) FROM Ratings WHERE model = m ) + WHERE + model = m; + + END -- +-- 2 + CREATE PROCEDURE DeleteRating ( IN cid ( 10 ), IN m ( 10 ), ) BEGIN + CALL RateModel ( p_customer_id, p_model, NULL ); + + END -- 3 + CREATE PROCEDURE CleanRatings ( INT cid ( 10 ) INT m ( 10 ) ) BEGIN + DELETE + FROM + Rating + WHERE + customer_id = cid + AND model = m + AND rating_time < ( + SELECT + max_time + FROM + ( SELECT MAX( r2.rating_time ) AS max_time FROM Ratings AS r2 WHERE r2.customer_id = p_customer_id AND r2.model = p_model ) AS t + ); + + END; + CALL RateModel ( '1122334455', '1001', 3 ); + CALL RateModel ( '1122334455', '1001', 2 ); + CALL RateModel ( '9999999999', '1001', 5 ); + CALL RateModel ( '1122334455', '1001', NULL ); + CALL RateModel ( '9999999999', '1001', 4 ); + CALL RateModel ( '9999999999', '1001', NULL ); + CALL RateModel ( '1122334455', '1001', 2 ); + CALL CleanRatings ( '9999999999', '1001' ); + CALL CleanRatings ( '1122334455', '1001' ); + + + + +-- 3 +CREATE VIEW AverageRatings(model, average_rating) +AS +SELECT + model, + COALESCE(SUM(rating) / COUNT(*), 0) AS average_rating +FROM Ratings +GROUP BY model +HAVING COUNT(*) > 0; -- 仅包含至少有1次评分的型号 + + +-- 3.b +DELIMITER // +CREATE FUNCTION BestModel() +RETURNS VARCHAR(20) +DETERMINISTIC +BEGIN + DECLARE max_avg FLOAT; + DECLARE best_model VARCHAR(20); + + -- 步骤1:获取最高平均评分 + SELECT MAX(average_rating) INTO max_avg FROM AverageRatings; + + -- 步骤2:若无评分,返回NULL + IF max_avg IS NULL THEN + RETURN NULL; + END IF; + + -- 步骤3:获取平均评分最高的所有型号,选择最新非空评分的型号 + SELECT model INTO best_model + FROM ( + -- 子查询:获取平均评分最高的型号,及其最新非空评分时间 + SELECT + ar.model, + MAX(CASE WHEN r.rating IS NOT NULL THEN r.rating_time ELSE NULL END) AS latest_non_null_time + FROM AverageRatings ar + JOIN Ratings r ON ar.model = r.model + WHERE ar.average_rating = max_avg + GROUP BY ar.model + ORDER BY latest_non_null_time DESC -- 按最新非空评分时间降序 + LIMIT 1 -- 取最新的一个 + ) AS temp; + + RETURN best_model; +END // +DELIMITER ; + + +-- 3.c \ No newline at end of file diff --git a/山东理工大学/其他/事件驱动.md b/山东理工大学/其他/事件驱动.md new file mode 100644 index 0000000..0932754 --- /dev/null +++ b/山东理工大学/其他/事件驱动.md @@ -0,0 +1,592 @@ +# C++ Key Topics Summary for Final Review (C++ 知识点期末复习总结 + +## Lecture 1: Introduction to C++ (第1讲:C++简介) + +**Key Concepts 主要知识点:** + +- **Machine Language(机器语言)** – The most basic programming language, consisting of binary code (0和1) directly executed by hardware. Machine code is **machine-dependent(与硬件相关)**; a program written for one type of CPU won’t run on another. +- **Assembly Language(汇编语言)** – Uses short English-like **mnemonics(助记符)** to represent machine instructions. Requires an **assembler(汇编器)** to translate into machine code. Assembly is easier to read than binary but still specific to a CPU architecture. +- **High-Level Language(高级语言)** – A programming language with English-like syntax and math-like notation. Examples: C++, Java. High-level code is portable and must be converted to machine code by a **compiler(编译器)** or run by an **interpreter(解释器)**. C++ is compiled into machine code (可编译成机器码执行), whereas Java is compiled to bytecode and run on the Java Virtual Machine (运行于JVM). +- **Phases of C++ Program Compilation(C++程序的编译阶段)** – C++ code undergoes several steps: **preprocessing(预处理)**, **compiling(编译)**, **linking(连接)**, and **loading(载入)**. The **preprocessor(预处理程序)** handles directives (like `#include`) before compilation. The **compiler(编译器)** translates source code to object code (machine instructions). The **linker(连接器)** combines your object code with libraries to produce an executable. The **loader(加载程序)** then loads the executable into memory for execution. +- **Object-Oriented Programming (OOP, 面向对象编程)** – C++ supports OOP, which involves organizing software as collections of **classes(类)** and **objects(对象)**. It emphasizes concepts like **encapsulation(封装)**, **inheritance(继承)**, and **polymorphism(多态)**. (Java is also OOP; C++ and Java share OOP concepts, but C++ allows lower-level memory control.) + +**After-class Exercises 课后练习:** + +1. **填空题:** 本章讨论的三种语言类型是 ***\**\*、\*\**\*** 和 ______。【提示】机器语言(machine language)、汇编语言(assembly language)和高级语言(high-level language)。 +2. **填空题:** 在C++系统中,______ 程序在编译器开始翻译之前执行。【提示】预处理程序(preprocessor)。 +3. **填空题:** ______ 程序将编译器的输出与各种库函数结合起来生成可执行程序。【提示】连接器(linker)。 +4. **填空题:** ______ 程序将可执行程序从磁盘传送到内存中准备运行。【提示】加载程序(loader)。 + +*Answers 答案:* 1) 机器语言, 汇编语言, 高级语言; 2) **预处理**程序; 3) **连接**程序; 4) **加载**程序。每个阶段各司其职,共同完成从源代码到可执行代码的转换。 + +## Lecture 2: Basic Syntax and Printing (第2讲:C++基本语法与打印) + +**Key Concepts 主要知识点:** + +- **Comments(注释)** – Non-executing text used to document code. `//` begins a **single-line comment(单行注释)**, and `/* ... */` encloses a **multi-line comment(多行注释)**. Comments improve readability and are ignored by the compiler (编译时会被忽略). (Java uses the same comment styles.) +- **Preprocessor Directive(预处理指令)** – Lines beginning with `#` (like `#include `) are processed by the preprocessor **before** compilation. For example, `#include ` inserts the declarations for input/output streams (输入输出流库) so we can use `std::cout` and `std::cin`. In C++, `` is analogous to Java’s `java.io` package, but C++ uses include files instead of import statements. +- **`main` Function(主函数)** – The entry point of a C++ program. Defined as `int main()` typically. The keyword **`int`** indicates main returns an integer status code to the system. In C++, `main` can be outside any class (不属于任何类), whereas in Java the entry point is a `public static void main` method within a class. +- **Statements and Semicolon(语句和分号)** – A **statement(语句)** is an instruction terminated by a semicolon `;`. C++ is a free-form language: you can use **whitespace(空白字符)** (spaces, tabs, newlines) to format code for readability; extra whitespace is generally ignored by the compiler. Each statement must end with `;` +- **Output with `std::cout`(使用cout输出)** – Use `std::cout << "text";` to print to the console. The `<<` is the **stream insertion operator(流插入运算符)**, sending data to the output stream. +- **Input with `std::cin`(使用cin输入)** – `std::cin` is the standard input stream (对应键盘输入). Using the extraction operator `>>`, as in `std::cin >> x;`, reads input into variable `x`. (Similar to Java’s `Scanner`, but C++ I/O is type-safe and reads whitespace-delimited tokens by default.) +- **Variables and Memory(变量与内存)** – A variable in C++ has a **name (identifier, 标识符)**, a **type(类型)**, and stores a value in memory. All variables **must be declared before use(先声明后使用)**. Common primitive types: `int` 整型, `double` 双精度浮点, `char` 字符型, `bool` 布尔型 (布尔值用`true`/`false`). C++ types correspond to Java’s primitive types, but note that boolean values in C++ can be implicitly converted to integers (true为1, false为0), whereas Java strictly separates `boolean` from numeric types. +- **Operators and Expressions(运算符与表达式)** – C++ supports arithmetic operators (`+ - * / %`), assignment operators (`=` and compound assignments like `+=`), and **relational operators(关系运算符)** (`== != < > <= >=`) for comparisons. Also logical operators (`&& || !`) for boolean logic. These work similarly to Java. One difference: In C++ you can use an `int` or other numeric in a condition (非零即真, 0为假), but in Java the condition of an `if` or loop must strictly be a boolean expression. +- **`if` Statement(条件语句)** – Allows decision-making. **`if`** executes a block if a condition is true. **`if...else`** chooses one block if condition true, otherwise the else-block (如果条件为假则执行else部分). In C++, as in Java, conditions use `==` for equality (注意避免将`=`误用在条件判断中). C++99 introduced a **bool** type, so modern C++ uses `true/false` similarly to Java, but older C style (如使用0和1表示真假) is still valid. +- **`return` Statement(返回语句)** – Ends a function and returns a value. In `main`, `return 0;` typically indicates successful execution. If omitted in C++ `main`, it defaults to 0. (Java’s `main` is `void`, so it doesn’t return a value to the system.) + +**After-class Exercises 课后练习:** + +1. **填空题:** 每个C++程序的执行从函数 ______ 开始。【提示】C++程序从`main`函数开始执行。 +2. **填空题:** 大多数C++语句以 ______ 结束。【提示】C++语句以分号(`;`)结束。 +3. **判断题:** 转义序列`\n`通过cout输出时会将光标移动到下一行开头。(对/错)【提示】`\n`表示换行,输出它会换行,**因此表述正确**。 +4. **判断题:** 所有变量在使用之前都必须先声明。(对/错)【提示】C++要求变量先声明再使用,**该说法正确**。 + +*Suggested Answers 答案:* 1) **main**; 2) **分号** (即每条语句末尾加`;`); 3) 对。`\n`是换行符,会使输出换到新行; 4) 对。在C++中必须先定义变量类型和名称,然后才能赋值或使用它。请注意区分赋值运算符`=`和相等比较运算符`==`,避免在条件判断中误用。 + +## Lecture 3: Classes, Objects and Strings (第3讲:类、对象与字符串) + +**Key Concepts 主要知识点:** + +- **Class(类)** – A blueprint for creating objects (对象模版). A class defines a new **data type(数据类型)** that groups data and functions. For example, `class GradeBook { ... };` defines a `GradeBook` class. A class contains **data members(数据成员)** (also called **attributes 属性** or **fields 字段**) and **member functions(成员函数)** (also called **methods 方法**). By default, class members are **private(私有)** in C++ (only accessible by the class’s own functions). Public interface is declared after the `public:` label. *(Java类默认成员可见性不同,Java中成员缺省是包可见,而C++类缺省是private。)* +- **Object(对象)** – An instance of a class. When you create an object, e.g., `GradeBook myGradeBook;`, it allocates memory for the data members and allows you to call member functions on it. Each object has its own copies of the class’s non-static data members (每个对象都有自己的一份数据成员). In OOP, an object’s data should usually be kept private, accessed only via the class’s public member functions (**encapsulation 封装**原则). +- **Member Function(成员函数)** – A function defined inside a class, describing behaviors or operations on class data. For example, `displayMessage()` might print a welcome message stored in a `GradeBook` object. Member functions can be defined inside the class definition or separately (using the scope resolution operator `ClassName::functionName`). By default, member functions are not **virtual(虚拟)** unless specified (see Lecture 11 for polymorphism details). *(Java的方法默认是虚拟(可覆盖)的,但C++需要明确使用`virtual`才能实现运行时多态。)* +- **Access Specifiers(访问说明符)** – Keywords like `public`, `private`, and `protected` that control access to class members. **`public` 公有** members are accessible from outside the class (接口API), while **`private` 私有** members are hidden from outside (只能被该类的成员函数访问). C++ class definitions often list public functions first (interface) and keep data members private. *(Java有类似的public/private修饰符,还有protected和默认访问级别; C++的protected在继承时用,后续讲解。)* +- **CamelCase Naming(驼峰命名)** – By convention, C++ class names start with a capital letter and use capital letters to distinguish words (e.g., `GradeBook`), whereas function names typically start with lowercase (e.g., `displayMessage`). This is a stylistic convention to improve code readability (在代码中区分类名和函数名). Java uses a similar convention (类名首字母大写,方法名首字母小写). +- **Constructors(构造函数)** – A special class member function that has the same name as the class and is used to initialize new objects (初始化对象). A **default constructor(默认构造函数)** is one that can be called with no arguments (either because it has no parameters or all parameters have default values). Constructors have no return type (not even void). In C++, if you do not define a constructor, the compiler provides a default constructor. Constructors are often used to set initial values for data members when an object is created. +- **`string` Class(字符串类)** – C++ provides `std::string` (in `` header) to represent text strings. You can create strings like `string s = "hello";` and use `s.length()` or `s.size()` for length, `s[0]` for character access, etc. This is similar to Java’s `String` class, but C++ `std::string` is mutable (可变的) and uses value semantics (copy on assignment) unless otherwise specified. Older C-style strings use char arrays terminated by `'\0'`, but `std::string` is safer and easier. *(Java的String是不可变对象; C++的std::string可以修改内容,例如`s.append("!");`添加字符。)* +- **Getters and Setters(访问器和修改器)** – It’s common to provide public member functions to **get** and **set** private data members. For example, a `GradeBook` class might have `getCourseName()` and `setCourseName()` to access a private `courseName` attribute. This preserves encapsulation by controlling how outside code interacts with class data. *(Java亦如此,通常用getX/setX方法访问私有字段。)* +- **Separating Interface and Implementation(头文件与实现)** – C++ practice is to put class definitions in a header file (e.g., `GradeBook.h`) and function implementations in a `.cpp` file, then include the header where needed. This separation allows multiple source files to include the class definition without duplication. Java does not separate interface and implementation in the same way; Java class definitions (fields and method signatures and bodies) are all in one `.java` file, but C++ encourages dividing the declaration (.h) and implementation (.cpp). + +**After-class Exercises 课后练习:** + +1. **填空题:** 每个类定义都以关键字 ______ 开头,后面紧跟类名。【提示】定义类以`class`开头,例如`class ClassName`。 +2. **填空题:** 类定义通常存储在文件以 ______ 扩展名结尾的文件中,以便被多处引用。【提示】头文件通常以`.h`或`.hpp`结尾。 +3. **填空题:** 当每个对象都有自己的某个属性副本时,这种属性变量也称为 ______ 。【提示】实例成员变量,即**数据成员**。 +4. **填空题:** 关键字`public`是一种 ______ 。【提示】`public`是访问说明符(access specifier)。 +5. **判断题:** 按照惯例,函数名应以大写字母开头,每个单词首字母大写。(对/错)【提示】函数名一般**不**以大写开头,而是首字母小写,所以该说法是**错**的。 +6. **判断题:** 函数定义中紧随函数名的空括号表示该函数不需要任何参数即可执行。(对/错)【提示】空参数列表表示无参数,该说法**正确**。 +7. **判断题:** 用`private`声明的数据成员或成员函数对该类的其他成员函数也是不可见的。(对/错)【提示】私有成员对本类的函数是可访问的,对类外才不可见,所以表述**错误**。实际上,private成员可以被本类的成员函数访问。 +8. **判断题:** 在某成员函数内部定义的变量称为数据成员,可以被该类的所有成员函数使用。(对/错)【提示】在函数内部定义的变量是**局部变量**,只能在该函数内部使用,不是整个类的成员,所以**错误**。 +9. **判断题:** 每个函数体都由左花括号`{`开始、右花括号`}`结束。(对/错)【提示】函数体需用`{}`包围,**正确**。 +10. **编程题:** *Invoice*(发票)类设计:创建一个名为Invoice的类以表示商店售出的某项商品的发票。这个类应包含以下私有数据成员: 商品编号(字符串), 商品描述(字符串), 购买数量(int), 单价(int)。为每个数据成员提供成对的`set`和`get`函数。此外,提供一个构造函数用于初始化所有成员,并提供一个名为`getInvoiceAmount`的成员函数来计算发票总额(即数量乘以单价)并返回该值(int)。如果购买数量或单价为负,则将其设为0再计算总额。**要求:** 翻译以上需求,并给出实现提示。 + +## Lecture 4: Control Statements (第4讲:控制语句) + +**Key Concepts 主要知识点:** + +- **Algorithm(算法)** – A procedure or formula for solving a problem, consisting of a sequence of actions in a specific order (一系列有序执行的操作). Writing an algorithm in simple steps before coding helps in program design. + +- **Pseudocode(伪代码)** – An informal, English-like way to describe an algorithm’s steps. Pseudocode is not actual code; it omits syntactic details and focuses on logic. It helps to plan programs without worrying about language syntax. (书写伪代码有助于先理清思路,再将其转换为真正的C++代码。) + +- **Control Structures(控制结构)** – Basic constructs that dictate the flow of program execution. All programs can be built using three fundamental structures: **sequence(顺序执行)**, **selection(选择执行)**, and **iteration(循环执行)**. C++ (like Java) has corresponding **control statements(控制语句)** for each: + + - **Sequence 顺序结构:** The default execution order where statements run one after another in the order written (顺序执行每条语句). + - **Selection 选择结构:** Making decisions. C++ provides **`if` 单分支** and **`if...else` 双分支** statements, and the **`switch` 多分支** statement for multi-way branching. The `if` statement executes a block if a condition is true; `if...else` chooses between two blocks. The `switch` statement tests an integer (or enum/char) expression and executes the case matching that value (each `case`标签后跟要执行的语句块). *Java’s `switch` is similar but can also use strings; C++17开始也允许`switch`字符型或枚举型,传统C++中`switch`不支持字符串。* + - **Iteration 循环结构:** Repeating actions. C++ has **`while`** and **`for`** loops (可能执行零次或多次) and a **`do...while`** loop (至少执行一次). A **`while` loop(当型循环)** repeats as long as a condition remains true (先检查条件,再执行循环体). A **`for` loop(计数循环)** is typically used for a known number of iterations, with initialization, condition, and increment in one line. A **`do...while` loop(后测试循环)** executes the body first, then checks the condition to decide if it should repeat. In all these, a loop condition works like an `if` condition: in C++ nonzero means true, zero means false. *(Java的循环与C++基本一致,也有`while`, `for`, `do...while`,但注意Java中必须使用布尔表达式作为循环条件,C++中整数也可作为条件使用。)* + +- **`if` and `if...else` (条件语句)** – The `if` structure allows conditional execution. Syntax: + + ```cpp + if (condition) { + // true block + } else { + // false block + } + ``` + + If the **condition(条件)** is true (非0或`true`), the first block executes; otherwise the `else` block executes (if present). Use braces `{}` to group multiple statements in a block. *良好习惯:即使只有一条语句,也使用花括号以避免歧义(Good practice to always use braces for clarity).* You can nest ifs for multiple levels of decision (嵌套的if结构处理更复杂的条件). + +- **`switch` Statement(多路分支)** – Used for multi-way branching based on an integer or enum expression. Syntax: + + ```cpp + switch (expression) { + case constant1: + // statements + break; + case constant2: + // statements + break; + ... + default: + // statements + } + ``` + + The **`case` labels(分支标签)** must be constant expressions. The `switch` transfers control to the matching case. Without an explicit `break`, execution will “fall through” to the next case (贯穿后续case). Typically, each case ends with `break` to prevent fall-through (除非有意连续执行). The `default` label handles any value not matched by cases. *(Java的switch相似,但在Java中使用字符串作为case是允许的,而传统C++不直接支持字符串。无论C++还是Java,都需要break避免贯穿。)* + +- **Loops(循环)** – Three types in C++: + + - **`while` loop(当型循环)**: Checks condition first, then executes loop body if condition is true. Continues checking and executing until condition becomes false. Example: `while (x > 0) { x--; }`. If condition is initially false, the loop body may not execute at all. + + - **`do...while` loop(至少执行一次的循环)**: Executes the loop body **at least once** and then checks the condition at the end. Syntax: + + ```cpp + do { + // body + } while(condition); + ``` + + Useful when the loop body should run at least one time (例如菜单处理,需要先显示菜单再判断是否重复). + + - **`for` loop(计数循环)**: Typically used when the number of iterations is known or to iterate over a range. Syntax: + + ```cpp + for ( initialization; condition; increment ) { + // body + } + ``` + + Example: `for(int i=0; i<5; ++i) { ... }` will loop 5 times (i从0到4). The `for` loop is essentially a compact form of a while: initialization executes once at loop start, then each iteration checks condition and executes body, then performs increment step. C++11 adds a **range-based for loop(基于范围的for循环)**, e.g., `for(int val : array) { ... }`, to iterate over containers/arrays easily (类似Java增强for循环). + +- **`break` and `continue`** – Within loops (以及switch中), **`break`(跳出)** immediately exits the loop (终止当前循环), and **`continue`(继续下轮)** skips the remaining statements in the loop body and proceeds with the next iteration (提前进入下一次循环判断). Use these carefully to avoid confusing flow. *(Java中break/continue语义相同。)* + +- **Logical Operators(逻辑运算符)** – `&&` (AND), `||` (OR), and `!` (NOT) are used to form complex conditions (组合多个条件). They work similarly to Java, including short-circuit evaluation (短路求值): in `expr1 && expr2`, if `expr1` is false, `expr2` is not evaluated at all. Likewise for `||`: if the first operand is true, the second is skipped. Use parentheses to clarify logic when needed. + +- **Compound Assignment(复合赋值)** – Operators like `+=`, `-=`, `*=`, `/=`, `%=` for combining arithmetic with assignment. E.g., `x += 5;` adds 5 to x (相当于 `x = x + 5;`). These make code concise. C++ also has **increment/decrement operators(自增/自减)**: `++x` or `x++` to add 1, `--x` or `x--` to subtract 1. Prefix (`++x`) vs postfix (`x++`) matters in expressions (前置返回新值, 后置返回旧值), but as standalone statements both increment x. (Java also has these operators with the same behavior.) + +- **Data Type Portability(数据类型可移植性)** – An awareness point: Fundamental types like `int` may have different sizes on different platforms (e.g., 32-bit vs 64-bit systems). C++ defines minimum ranges (e.g., `int` at least ±32,767) but not exact sizes in the language standard. Java’s primitive types have fixed sizes (e.g., int is always 32-bit) making them more portable across platforms. C++11 introduced fixed-width types (如`int32_t`) in `` for precise control when needed. + +- **Boolean context(布尔上下文):** In C++, an `int` or pointer can be used in a boolean context (非零即真), whereas Java requires a true boolean value for conditions (在Java中使用非boolean作为条件会编译错误). For example, `while(n)` is valid in C++ (loops while n≠0), but in Java you must write `while(n != 0)`. +- **Switch limitations(switch的限制):** C++ `switch` can use integral types (int/char/enum) but not strings or objects. Java’s `switch` (since Java 7) allows `String` and wrapper types. Also, C++ does not automatically break at the end of a case (必须手工`break`防止贯穿), same as Java. Both languages support a `default` case. +- **Loop features:** Both anguages support `break` and `continue` inside loops. Java adds labeled breaks/continues; C++ doesn’t have labeled loop control (no equivalent to Java’s `label:` with break label). +- **for-each loop:** Modern C++ (`range-based for`) is akin to Java’s enhanced for loop for arrays/collections. Syntax differs slightly but concept is the same (iterate through elements directly). +- **do...while:** Present in both languages with identical behavior (loop executes at least once). +- **No implicit type conversion to boolean in Java:** Java不会将数字自动转为布尔,这在C++中需要注意,如果将C++代码移植到Java,要显式比较==0或!=0。 +- **Precision of types:** As mentioned, Java’s types have fixed size (e.g., `int` 32-bit), whereas C++’s may vary; this can affect loop ranges or portability if you assume a certain size in C++. + +**After-class Exercises 课后练习:** + +1. **判断题:** 在`if`语句中,若条件不加括号也能正常编译运行。(对/错)【提示】条件必须放在圆括号内,漏写括号会导致语法错误,**错误**。正确格式如:`if (x > 0) {...}`。 + +2. **判断题:** 在`switch`的每个`case`分支后都应使用`break`来防止执行落入下一个分支。(对/错)【提示】一般应加`break`避免“贯穿”行为,**正确**。如需特意贯穿,可以省略,但必须十分小心。 + +3. **判断题:** 在`for`循环中使用`continue`语句会提前跳出整个循环。(对/错)【提示】`continue`只是跳过本次余下循环并进入下一次迭代,不会终止循环,**错误**。结束整个循环应使用`break`。 + +4. **编程题:** **判断回文数(Palindrome)** – 定义一个函数`bool isPalindrome(string str)`,如果字符串正着读和反着读都相同则返回`true`,否则返回`false`。例如:"madamimadam"是回文。请将此函数补充完整。 + + **提示:** 所谓“回文”指序列从前往后和从后往前相同。解决思路:可以使用两个索引分别从字符串头部和尾部向中间移动,逐字符比较是否相等。一旦发现对应字符不相等,就可以断定不是回文。若所有字符成对匹配,则是回文。如: + + ```cpp + bool isPalindrome(string str) { + int i = 0, j = str.length() - 1; + while(i < j) { + if(str[i] != str[j]) + return false; + i++; + j--; + } + return true; + } + ``` + + 此函数遍历字符串的一半长度即可完成判断,时间复杂度为O(n)。在调用时可传入数字的字符串形式进行判断(也可以先将int转换为string再调用)。*(In Java, one could similarly check by comparing `str.charAt(i)` and `str.charAt(j)` in a loop.)* + +## Lecture 5: Functions, Recursion and Overloading (第5讲:函数、递归与重载) + +**Key Concepts 主要知识点:** + +- **Functions(函数)** – Named blocks of code that perform a specific task, improving modularity (模块化) and reuse. Functions in C++ can be **standalone (free) functions(自由函数)** or member functions of classes. A function **definition(定义)** consists of a return type, name, parameter list, and body. A **function call(调用)** executes the function’s body. For example, `int add(int a, int b) { return a+b; }` defines a function `add` that returns an int sum, and you call it as `int result = add(3,4);`. Functions allow **divide-and-conquer programming** by breaking a program into smaller pieces. *(Java的方法类似,但Java没有独立的全局函数,所有方法必须属于类;C++既有类成员函数也允许全局函数定义。)* +- **Function Prototype(函数原型)** – A function declaration that specifies the function’s interface (name, return type, parameters) without the body. For example, `int add(int, int);` is a prototype. Prototypes (often placed in headers) allow the compiler to know about a function before its definition appears, enabling calls from code that comes lexically before the function’s definition. The compiler uses the prototype to verify calls (参数类型和数量是否匹配) and perform **type coercion(类型转换)** for arguments if needed. In C++, you **must** either declare or define a function before calling it (Java doesn’t require forward declarations because the one-pass compiler or JIT knows all class methods by design). +- **Parameters and Arguments(形参与实参)** – **Parameters(形式参数)** are variables declared in the function definition/prototype to receive data, and **arguments(实参)** are the actual values passed to the function when called. The number, order, and types of arguments must match the function’s parameters (except where default parameters are used). C++ evaluates arguments left-to-right (evaluation order unspecified in older C++ standards, but guaranteed in C++17). By default, C+。+ uses **pass-by-value(值传递)**, meaning the function gets a copy of the arguments (函数操作形参不会影响调用者提供的实参变量). You can also use **pass-by-reference(引用传递)** or pointers to allow the function to modify caller variables (e.g., `void foo(int &x) { x = 5; }`). *(Java方法参数传递都是值传递,但对象引用作为值传递可以间接修改对象的内容。Java没有C++引用这种语法,但对象参数可改变其内部状态。)* +- **Return Value(返回值)** – The value a function gives back after completion, specified by the function’s return type. Use the `return` statement to return a value and exit the function. If a function is declared with a non-void type, it should return a value of that type. If the function is `void`, it does not return a value (though it can use `return;` to exit early). In C++, failing to return a value from a non-void function results in undefined behavior (Java would not compile such a method). +- **Void Functions(void函数)** – Declared with `void` return type, they do not return any value. They typically perform actions like printing or modifying global state. For example, `void printMessage() { cout<<"Hi"; }`. You call it as `printMessage();` and there’s no result to use. (Java’s `void` methods are analogous.) +- **Local and Global Variables(局部和全局变量)** – **Local variables(局部变量)** are those defined inside a function (including parameters), which exist only during function execution and are not known outside. Each call creates new instances of local variables (stored on the **stack 栈**). **Global variables(全局变量)** are defined outside any function, accessible from any code after their declaration (unless restricted by `static` or namespaces). Global variables in C++ have program duration (allocated in static storage). It’s good practice to minimize globals for modularity. +- **Storage Class and Lifetime(存储类与生命周期)** – C++ variables have storage durations: **automatic(自动存储期)** for locals (allocated on function entry, freed on exit), **static(静态存储期)** for globals and `static` local variables (allocated when program starts or when first encountered for local statics, freed at program end), and **dynamic(动态存储期)** for memory allocated via `new` (lives until `delete`). For example, a `static int count;` inside a function retains its value between calls (第一次调用时初始化一次,以后调用保留之前的值). Java manages object lifetimes with garbage collection and has no direct equivalent to C++ manual memory allocation in terms of keywords (no `new`/`delete` pairing visible to programmer; Java’s `new` automatically managed by GC). +- **Math Library Functions(数学库函数)** – C++ `` header provides common functions like `sqrt()`, `pow()`, `sin()`, etc. These are global (not class members) and can be called by including `` and writing e.g. `double r = sqrt(4.0);`. (Java has similar math functions in `java.lang.Math` as static methods, e.g., `Math.sqrt(4.0)`). +- **Function Overloading(函数重载)** – C++ allows multiple functions with the **same name** but different parameter lists (不同的参数签名) in the same scope. The compiler distinguishes them by their **signature(函数签名)** – the combination of function name and parameter types (顺序及数量). For example, you can have `int max(int,int)` and `double max(double,double)`. When you call `max(3,5)`, the int version is invoked; `max(3.5, 4.2)` calls the double version. Overloading lets you use a common name for conceptually similar operations on different types. *(Java also supports method overloading in classes. In both languages, return type alone is not enough to overload; 参数列表必须不同。)* The compiler uses **name mangling(名字改编)** under the hood to encode parameter types in the symbol name, enabling type-safe linkage. +- **Default Arguments(默认参数)** – C++ allows you to specify default values for parameters in function declarations. For instance, `void print(int count = 1)` means if `print()` is called without an argument, `count` will default to 1. Default arguments must be the rightmost parameters, and if you omit one argument in a call, you must omit all to its right. Java does not have default parameters; instead, you overload methods to achieve similar behavior. *(注意:默认参数值在函数声明处给出,在调用时若不传该参数则使用默认值。)* +- **Inline Functions(内联函数)** – Declared with the keyword `inline` (or defined directly in class definition for member functions), these suggest to the compiler to expand the function body at the call site to avoid function call overhead. Useful for very short functions. Modern compilers optimize short functions automatically, so explicit `inline` is less critical. (Java inlining is handled by the JIT at runtime and not exposed in source.) +- **Recursion(递归)** – A programming technique where a function calls itself (直接或间接调用自身). Recursive solutions have a **base case(基例)** that stops recursion and one or more **recursive cases(递归情况)** where the function calls itself with a smaller sub-problem. For example, the factorial function can be defined recursively: `factorial(n) = n * factorial(n-1)` with base case `factorial(0)=1`. Each recursive call has its own set of local variables (stack frame) on the **function call stack(调用栈)**. If recursion doesn’t converge to a base case, it results in infinite recursion (类似无限循环) and eventually a stack overflow (栈内存溢出). Recursion can produce elegant solutions for problems like factorial, Fibonacci, tree traversal, etc., but iterative solutions (使用循环) may be more efficient in some cases. C++ and Java both support recursion similarly. +- **Recursive vs Iterative(递归与迭代对比)** – Both recursion and looping achieve repetition. **Iteration(迭代)** explicitly uses loops, modifying loop variables until a condition fails. **Recursion** uses repeated function calls, letting the runtime handle looping via the call stack. Recursion can be more readable for divide-and-conquer algorithms (分治算法), but each function call has overhead. For example, calculating Fibonacci recursively leads to many duplicate subcalls, whereas an iterative approach or memoization is more efficient. It’s important to choose the right approach based on clarity and performance. *(在Java中也是如此,递归容易栈溢出且有函数调用开销,但写法简洁; 有些算法(如遍历树结构)递归实现更直观。)* + +**After-class Exercises 课后练习:** + +1. **填空题:** 只在定义所在函数内可见的变量称为 ______ 变量。【提示】这类变量是局部变量(local variable)。 + +2. **填空题:** 在被调用函数中使用 ______ 语句可以将表达式的值传回调用函数。【提示】使用`return`语句返回值。 + +3. **填空题:** 函数头中使用关键字 ______ 表明该函数不返回任何值。【提示】`void`关键字。 + +4. **填空题:** 可以定义多个同名但参数不同的函数供不同数据类型使用,这称为函数 ______ 。【提示】**函数重载** (function overloading)。 + +5. **填空题:** 使用限定符 ______ 声明的变量为只读变量(不能被修改)。【提示】用`const`限定符声明常量。 + +6. **判断题:** 一个类可以定义多个与类同名的函数来构造对象。(对/错)【提示】**对**。类可以有多个构造函数,参数不同即构成重载。 + +7. **判断题:** 如果函数参数需要多个值,那么函数调用时参数和形参在类型、顺序和数量上必须一一对应。(对/错)【提示】**对**。实参会按照位置依次匹配形参,类型必须兼容或可转换,否则编译错误。 + +8. **判断题:** 用关键字`inline`声明的函数编译后一定会内联展开,不会发生函数调用开销。(对/错)【提示】**错**。`inline`只是建议,具体是否内联由编译器决定。另外,即使没声明inline,编译器有时也会优化内联。 + +9. **判断题:** 递归和迭代都会重复执行操作,但递归可能导致较高的函数调用开销和内存占用。(对/错)【提示】**对**。递归调用频繁压栈出栈,开销较大;迭代通常更节省资源。如果递归层次太深还可能导致栈溢出。 + +10. **找错改错:** 下列代码包含若干错误,请说明并更正。 + + ```cpp + void g() { + cout << "Inside function g" << endl; + void h() { + cout << "Inside function h" << endl; + } + } + float cube(float); // function prototype + cube(float number) { + return number * number * number; + } + ``` + + **提示:** 存在两个主要错误:首先,C++中不允许在函数`g`内部定义另一个独立的函数`h`(不能在函数内嵌套定义函数)。应将`h`的定义移到`g`外部。同理,每个函数的花括号必须匹配,`g`函数在定义`h`之前就应该闭合其作用域。其次,`cube(float number)`函数的定义缺少返回类型,应与前面的原型一致返回`float`。修改如下: + + ```cpp + void g() { + cout << "Inside function g" << endl; + } + void h() { + cout << "Inside function h" << endl; + } + float cube(float number) { + return number * number * number; + } + ``` + + 以上更正包括:将`h`定义为独立的`void h()`函数,并为`cube`函数添加返回类型`float`使其与声明匹配。此外,确保每个函数的定义都有匹配的花括号闭合。经过修改,代码可正常编译,函数调用关系也清晰明确。 + +## Lecture 6: Arrays and Vectors (第6讲:数组与向量) + +**Key Concepts 主要知识点:** + +- **Array(数组)** – A collection of elements of the **same type(相同类型)** stored contiguously in memory. Think of an array as a series of numbered boxes, each holding a value of a particular type. You refer to an element by its **index(索引/下标)**, an integer offset from the start of the array. In C++ (and many languages), array indexing starts at **0** (首元素索引为0). For example, if `int a[5];` is an array of 5 ints, valid indices are 0 through 4. The number inside `[]` is the array’s length (元素数量). + - **Declaring Arrays(数组声明)**: Use syntax `Type arrayName[arraySize];`. This allocates memory for `arraySize` elements of `Type`. The size must be a constant expression (编译时常量) in C++ for static arrays. It’s recommended to use a constant or `#define` for array sizes to avoid “magic numbers” (不直接使用字面值) in the code. + - **Accessing Elements(访问元素)**: Use the subscript operator `[]`, e.g., `a[2]` refers to the third element of array `a`. Indices must be integers (or integer expressions). Be careful: C++ does **not perform bounds-checking(不自动检查下标越界)** on array accesses. Accessing an out-of-range index causes undefined behavior (可能读取无效内存或导致程序崩溃). In contrast, Java throws an exception if you index out of bounds. Always ensure index `0 <= index < arrayLength`. + - **Initializing Arrays(数组初始化)**: You can initialize an array when you declare it. For example: `int b[3] = {1, 2, 3};` or `int c[5] = {0};` (initializes all 5 elements to 0). If the initializer list has fewer elements than the array, remaining elements are initialized to 0 (implicitly). If the array size is omitted, the compiler deduces it from the initializer count. *(Java数组初始化类似,但Java数组是对象,在运行时动态分配; C++静态数组在栈或静态存储上分配。)* + - **Constant for Array Size(常量数组长度)**: It’s good practice to use a `const` variable for array size, e.g., `const int SIZE = 10; int arr[SIZE];`. This makes the code more maintainable (eliminates “magic number”) and clearly communicates the array length. Note: In modern C++ you can also use `std::array` or `std::vector` which manage size dynamically or at compile time. +- **Array Index (Subscript)(数组下标)** – The index is the position of an element. Also called **subscript(下标)**. The first element is index 0, last element index = size-1. Using an index outside this range leads to invalid memory access (C++不会自动抛异常,因此务必小心)。For example, if `int a[5];`, `a[5]` is an invalid access (有效索引为0~4)。 +- **Memory Layout(内存布局)** – Arrays are stored in contiguous memory. If `a` is an `int[5]`, and on a system `int` is 4 bytes, then `a[0]` is at some address `p`, `a[1]` is at `p+4`, `a[2]` at `p+8`, etc. Pointer arithmetic can be used with arrays (Lecture 7). C++ does not store the array length with the array (unlike Java which has `array.length` property). You must track the size separately. +- **Constant vs Variable Length Arrays**: Traditional C++ (pre-C++11) required array size to be a compile-time constant for stack allocation. Some compilers allow variable length arrays (VLAs) as an extension, but the portable way for dynamic size is to allocate on heap or use `std::vector`. *(Java数组长度是在运行时确定的,通过`new`分配,C++也可以用`new`动态分配数组,或使用标准容器。)* +- **Arrays Initialization Pitfalls(初始化注意)**: If you partially initialize (e.g., `int d[5] = {1,2};`), uninitialized elements are set to 0 in C++ for static storage or if initializer list is provided. However, if you omit an initializer entirely for a local array, the array contains **garbage values(未定义垃圾值)**. Always initialize or set values before use. +- **const Arrays(常量数组)**: Declaring an array as `const` (e.g., `const int arr[3] = {…};`) makes its elements read-only. Alternatively, using `constexpr` for compile-time constant arrays. (Java has final arrays references, but array elements can still change unless individually final; C++ const truly makes each element constant.) +- **Multidimensional Arrays(多维数组)** – C++ allows arrays of arrays, e.g., `int matrix[3][4];` is a 3x4 matrix (3 rows, 4 columns). Access via `matrix[i][j]`. These are stored in row-major order (行优先存储). You must specify sizes for all but the first dimension when passing to functions. Java’s multi-dimensional arrays are actually arrays of array objects (could be ragged), while C++ multi-dimensional arrays are true multi-dimension in contiguous memory (unless you use pointers to simulate jagged arrays). +- **Static vs Automatic Arrays**: A **static local array(静态局部数组)** (declared with `static` inside a function) persists for the program’s lifetime and is zero-initialized by default. An **automatic array(自动/局部数组)** (normal local array) is created each time the function is called and destroyed on exit; it is not automatically initialized (contents are indeterminate if not set). Use static when you need to preserve values between calls or for large arrays to avoid stack usage (but then not thread-safe). +- **Range-Based for (C++11)(基于范围的for循环)** – You can loop through an array easily: `for(int x : arr) { ... }` will iterate over each element `x` in `arr`. This is similar to Java’s enhanced for: `for(int x : arr)`. It’s read-only by default (x is a copy). Use reference (`for(int &x : arr)`) if you want to modify array elements in the loop. +- **No Built-in Bounds Checking(无边界检查)** – Unlike Java, C++ will not throw an error if you go out of bounds on an array; it will just access whatever memory is at that address. This can lead to bugs or security issues. For safer arrays, use `std::array` (which has `.at(index)` that throws an exception on out-of-range) or `std::vector` (with `at` method). In critical applications, consider using these or adding manual checks. +- **C-Strings vs std::string**: A C-style string is an array of `char` ending with `'\0'`. e.g., `char name[6] = "Alice";` (actually 6 elements including null terminator). Manipulating C-strings requires care (functions in `` like `strcpy`, `strlen`). `std::string` (as covered in Lecture 3) is higher-level and easier to use. When interacting with C APIs, you might convert `std::string` to C-string via `c_str()` method. +- **Class Template `std::vector`(向量模板类)** – A dynamic array provided by the C++ Standard Library (in header ``). **`std::vector`** represents a resizable array of elements of type T. Key features: + - **Dynamic sizing(动态大小)**: It can grow or shrink at runtime. Start with `vector v;` and use `v.push_back(value);` to append elements. The vector manages its own memory (automatically allocates more space as needed). + - **Access and Capacity(访问与容量)**: Use `v[index]` to access elements (like array, but no bounds check by operator[]), or `v.at(index)` which throws `std::out_of_range` exception if index is invalid. Use `v.size()` to get current number of elements. Unlike built-in arrays, `vector` knows its length. + - **Initialization**: You can initialize with a size: `vector v(10);` creates a vector of size 10 (elements default-initialized, e.g., 0 for int). Or initialize with values: `vector v = {1,2,3};`. + - **Comparison**: Vectors can be compared with `==` and `!=` (element-wise comparison). Two vectors are equal if they have same length and all corresponding elements equal. + - **Copy and Assignment(拷贝与赋值)**: You can assign one vector to another (`v2 = v1;`) and it copies all elements (深度复制,每个元素都会被拷贝). There is also a copy constructor (e.g., `vector v2(v1);`) to initialize from another vector. + - **Memory Reallocation**: Vectors manage an internal capacity. They might allocate more capacity than size for efficiency. When size exceeds capacity, a reallocation happens (which can move the data). Thus pointers/iterators to vector elements may be invalidated when reallocation occurs. (Java’s `ArrayList` is similar in this regard.) + - **Bounds Checking**: `vector::at` provides bounds checking. In contrast, `operator[]` does not check bounds (for performance). Java’s `ArrayList` `get(index)` does check and throws exception if out of range. + - **Default initialization**: A `vector v(5);` will value-initialize the 5 ints to 0, whereas a built-in array of 5 ints (if local) would be uninitialized unless explicitly set. + - **Iterators**: Vectors provide iterators (like pointers) to traverse elements. Example: `for(auto it = v.begin(); it != v.end(); ++it) { cout<< *it; }`. (Similar to Java iterators, but in C++ often we use range-for instead for simplicity.) + - **Advantages**: `std::vector` is safer and more flexible than raw arrays. Use it unless you have a specific reason to use C-style arrays. + +**After-class Exercises 课后练习:** + +1. **填空题:** 定义数组长度时应使用 ______ 来避免魔术数字(magic number)。【提示】应使用符号常量,例如`const`常量或宏。 + +2. **填空题:** 用来引用数组特定元素的数字称为该元素的 ______ 。【提示】称为**下标**或索引(subscript/index)。 + +3. **判断题:** 一个数组可以存储多种不同类型的值。(对/错)【提示】**错。**数组中的所有元素类型必须相同。例如,`int`数组只能存`int`,不能混存其它类型。 + +4. **判断题:** 数组的下标值通常应使用`float`类型,以便表示更大的范围。(对/错)【提示】**错。**数组下标应使用整数类型(如`int`),浮点数不可直接作为下标(编译时会转换或报错)。 + +5. **判断题:** 如果初始化列表中的初始值个数少于数组长度,未提供初始值的元素将被初始化为列表中的最后一个值。(对/错)【提示】**错。\**对于不足的部分,C++会将其\**初始化为0**(数值类型)而不是重复最后一个值。 + +6. **判断题:** 如果初始化列表中的值多于数组容量,这将导致编译错误。(对/错)【提示】**对。**初始化时初始值数量不能超过数组声明的大小,否则程序无法通过编译。 + +7. **编程题:** 定义一个大小为99的浮点数组`w`,写一个程序找出并输出该数组中的最小值和最大值。要求:给出中文解题思路。 + + **提示:** 可以通过一次遍历数组来同时找出最小值和最大值。具体步骤:先假设数组首元素既是最小值又是最大值,然后从第二个元素开始遍历整个数组,与当前最小值、最大值比较并更新。如伪代码: + + ``` + minVal = w[0], maxVal = w[0] + 对于 i 从 1 到 98: + 如果 w[i] < minVal,则 minVal = w[i] + 如果 w[i] > maxVal,则 maxVal = w[i] + 输出 minVal 和 maxVal + ``` + + 这样单次循环即可完成查找(时间复杂度O(n))。需要注意数组必须已填入有效的数值才能进行比较(未初始化元素不能直接比较)。在实现中,先对`w`赋值(可通过输入或随机生成等),然后应用上述逻辑得到结果。请确保访问数组时索引不越界(0到98)。*(The approach is similar in Java: one would use a loop from 0 to length-1, updating min and max accordingly.)* + +## Lecture 7: Pointers and Memory Management (第7讲:指针与内存管理) + +**Key Concepts 主要知识点:** + +- **Pointer(指针)** – A variable that holds a **memory address(内存地址)** as its value. If a variable `x` resides at some address in memory, a pointer can “point to” `x` by storing that address. In C++, pointers are declared with an asterisk `*`. For example, `int *p;` declares `p` as a pointer to int (能够存放某个整型变量的地址). Pointers provide **indirection(间接引用)**: they allow access to the object they point to. *(Java没有显式的指针类型;Java的引用在某种程度上类似指针,但不能进行算术运算或转换为整数地址。)* +- **Address-of Operator `&`(取地址运算符)** – A unary operator that yields the memory address of its operand. For example, if `int y = 5;` then `&y` gives the address where `y` is stored. You can assign that to a pointer: `int *yPtr = &y;` now `yPtr` contains y’s address. Think of `&` as “give me the location of”. +- **Dereference Operator `\*`(解引用/间接运算符)** – A unary operator used on a pointer to access the object it points to. For example, if `int *p = &y;` then `*p` refers to the same variable as `y`. So `*p = 10;` would set `y` to 10. `*` here is called the **indirection operator(间接访问运算符)**, and using `*p` is **dereferencing the pointer(解引用指针)**. *Important:* `*` has two roles in C++: declaration (to denote a pointer type) and dereferencing. The context differentiates them. *(Java does not allow direct pointer dereferencing; object references are automatically dereferenced with `.` operator to access fields/methods.)* +- **Pointer Declaration and Initialization(指针声明与初始化)** – When declaring multiple pointers in one statement, note that the `*` applies to each variable individually: e.g., `int *p, q;` declares `p` as pointer to int and `q` as int (not a pointer). It’s clearer to separate declarations. **Always initialize pointers(初始化指针)** when declaring if possible, either to a valid address or to `nullptr` (C++11) or `NULL` (older) or `0`. An uninitialized pointer contains an indeterminate address (野指针), dereferencing it causes undefined behavior. Setting a pointer to **null pointer(空指针)** indicates it points to nothing (a safe “nowhere” value). In C++ `NULL` is typically defined as 0; C++11 introduced `nullptr` as a type-safe keyword for null pointers. +- **Null Pointer(空指针)** – A pointer that is not pointing to any object or function. In C++ you can assign `0` or `NULL` to a pointer to make it null. Dereferencing a null pointer (`*p` when `p` is null) is invalid and will likely crash the program (访问空指针会导致运行时错误). Always check `if(p != nullptr)` (or `if(p)` since null is falsey) before dereferencing if unsure. (Java references throw `NullPointerException` if used when null; in C++ it’s just undefined behavior with no automatic check). +- **Pointer Arithmetic(指针算术)** – Pointers can be incremented or decremented (if they point to elements of an array). For example, if `p` is an `int*`, `p++` advances `p` to point to the next integer in memory (地址增加`sizeof(int)`字节). Likewise `p + n` moves the pointer forward by n elements. Pointer arithmetic is scaled by the pointed type size. So adding 1 to an `int*` moves 4 bytes (on typical 32-bit int system), adding 1 to a `double*` moves 8 bytes, etc. This is how C-style arrays and pointers are closely related (see next point). *(Java does not support pointer arithmetic at all. All array indexing in Java is done with the index and internal checks, not by moving pointers.)* +- **Arrays and Pointers Relationship(数组与指针的关系)** – In C++, the name of an array can decay to a pointer to its first element. For example, if `int a[10];`, then `a` (in most expressions) is treated as `int*` pointing to `a[0]`. So you can do `int *p = a;` and then `*(p+3)` is equivalent to `a[3]`. Also, `a[i]` is defined as `*(a + i)`. There is a close interplay: pointer arithmetic + dereference can simulate array indexing. Note: Arrays allocated with `new` (like `int *p = new int[10];`) should be accessed with pointer notation `*(p+i)` or as if `p` were array name `p[i]`. One key difference: a pointer is a variable (you can reassign it), but an array name is not a modifiable lvalue (不能给数组名赋新地址值). +- **Pointer vs Reference(指针与引用)** – C++ also has **references(引用)**, declared with `&` (e.g., `int &ref = x;`). A reference is an alias to an existing variable; once initialized to refer to a variable, it cannot be changed to refer to another. References are simpler (no deref operator needed: use `ref` directly as alias), but they cannot be null and must be initialized upon creation. Pointers, on the other hand, can be reassigned, can be null, and require explicit dereferencing. Both can be used for pass-by-reference to functions, but references are generally safer and preferred for that purpose. *(Java’s object variables are more like pointers “under the hood,” but Java doesn’t allow pointer arithmetic or direct memory access. Java’s references are automatically dereferenced; you don’t see an explicit `\*` as in C++.)* +- **Dynamic Memory Allocation(动态内存分配)** – Using **`new`** to allocate memory on the heap. For example, `int *p = new int;` allocates an `int` and returns a pointer to it. For arrays: `int *arr = new int[50];` allocates an array of 50 ints on heap. Complement with **`delete`** to free a single object (`delete p;`) or **`delete[]`** for arrays (`delete[] arr;`) to avoid memory leaks (内存泄漏). If `delete` is not called, the allocated memory remains occupied until program ends. *Java doesn’t have explicit `new`/`delete` pairing; it relies on garbage collector to reclaim unused objects.* +- **Memory Leaks and Dangling Pointers(内存泄漏与悬空指针)** – A **memory leak(内存泄漏)** occurs if heap memory is allocated and never freed (在C++中忘记调用`delete`就丢失了指针). Over time, leaks exhaust memory. A **dangling pointer(悬空指针)** is a pointer that refers to memory that has been freed or is otherwise invalid. For example, if you `delete p;` and then still use `p` (without resetting it) – it’s pointing to deallocated memory. Accessing it is undefined behavior. Best practice: after `delete p;` set `p = nullptr;` to avoid accidental use. Smart pointers from `` (like `std::unique_ptr`) help manage dynamic memory automatically (RAII idiom). +- **Pointer to Constant / Constant Pointer(常量指针/指向常量)** – C++ allows const qualifiers with pointers: + - `int * const p` is a constant pointer to int (指针自身是常量,不能改指向其他地址,但所指对象可变)。 + - `const int * p` (or `int const * p`) is a pointer to a const int (指向常量的指针,不能通过*p修改对象,但指针本身可变)。 + - `const int * const p` is a const pointer to a const int (指针和所指对象都不可修改). + These add compile-time safety (e.g., if a function shouldn’t modify what it points to, take `const T*`). Java doesn’t have an equivalent; final references in Java mean you can’t reassign the reference, but you can still modify the object’s contents if it’s mutable. +- **Function Pointers(函数指针)** – A pointer can also point to a function’s address. Declaration syntax: `int (*fp)(int, int) = &functionName;`. This is advanced but allows passing functions as arguments (similar to delegates or lambdas in higher-level terms; C++11 has lambdas which are often easier). *(Java prior to 8 didn’t have function pointers; Java 8 introduced lambda expressions and method references to achieve similar functionality.)* +- **Pointer Safety Enhancements (C++11)** – Use `nullptr` instead of `NULL` for clarity and type safety. Use smart pointers (`std::unique_ptr`, `std::shared_ptr`) to automatically manage `delete`. These are part of modern C++ best practices to reduce manual memory errors. + +**After-class Exercises 课后练习:** + +1. **填空题:** 一元运算符`&`称为取地址运算符,用于获取其操作数的 ______ 。【提示】获取变量的**内存地址**。 +2. **填空题:** 一元运算符`*`用于指针时称为间接运算符或解引用运算符,用于获取指针所指向的 ______ 。【提示】获取指针指向的**目标对象/值**。 +3. **填空题:** 可以直接赋给指针变量的唯一整数值是 ______ ,表示该指针不指向任何有效对象。【提示】整数0(即空指针 `NULL`/`nullptr`)。 +4. **判断题:** 在C++中,指针可以指向不同类型的变量,不需要类型匹配。(对/错)【提示】**错。**指针有类型,必须与所指对象类型一致或兼容(需要时可强制转换,但一般不安全)。例如,`int*`只能指向`int`或可转换为int的地址,不能直接指向`double`。 +5. **判断题:** 指针与数组紧密相关,数组名在大多数表达式中会转换为指向其首元素的指针。(对/错)【提示】**对。**数组名可视为指向数组首元素的地址,如`a`可以作为`&a[0]`使用。因此`*(a+1)`与`a[1]`等价。 +6. **判断题:** 使用`new`运算符分配的内存必须使用`delete`释放,否则会发生内存泄漏。(对/错)【提示】**对。**每次`new`都应有相应的`delete`,否则分配的堆内存无法回收,导致内存泄漏。可使用智能指针防止忘记释放。 +7. **判断题:** C++引用(reference)类似指针,但引用一旦绑定某对象后不可更改,且不能为NULL。(对/错)【提示】**对。**引用是对象的别名,必须初始化,一经绑定无法指向别的对象,且不存在“空引用”。指针则可以在任何时候指向其他对象或设为NULL。 +8. **判断题:** 将指针加1实际上使其指向下一个内存地址。(对/错)【提示】**错**(有细微差别)。指针加1后指向下一个同类型元素的位置,不一定是下一个字节地址,而是跨过当前类型大小的字节数。例如`int*`加1跳过4字节到下一个int地址。 + +## Lecture 8: Classes – Deeper Look (Part 1 & 2) (第8讲:更深入的类机制 上、下) + +**Key Concepts 主要知识点:** + +- **Separate Header and Implementation(头文件与实现分离)** – It is common to split a class into a **header file(头文件)** (`.h` or `.hpp`) and an **implementation file(实现文件)** (`.cpp`). The header contains the class definition (class declaration, with member function prototypes), and the implementation file contains the function definitions (函数定义) of those member functions. This separation aids maintainability: changes in implementation don’t force recompilation of code that includes the header (as long as interface remains unchanged). To use a class in multiple source files, you include the header. For example, `#include "GradeBook.h"` in any file using `GradeBook` class. *(Java没有头文件—接口和实现都在`.java`文件内; 但Java可以通过interface和implementation classes来分离定义。C++头/源分离更贴近编译过程需求。)* + +- **Default and Value Parameters in Constructors(构造函数默认参数)** – Constructors (and any function) in C++ can have **default arguments(默认参数)**. This allows one constructor to handle multiple cases. For instance: + + ```cpp + class Player { + public: + Player(string name = "Anonymous", int level = 1) { + this->name = name; + this->level = level; + } + }; + ``` + + With this, you can construct `Player p1;` (uses defaults "Anonymous",1), or `Player p2("Alice");` (level defaults to 1), or `Player p3("Bob",5);`. At most one default constructor exists per class (构造函数默认为一个,因为参数默认可组合成无参调用),which is one that can be called with no arguments. If you provide default values for all parameters of a constructor, that constructor becomes the default constructor. *Java doesn’t support default parameters; you must overload constructors instead.* + +- **Destructor(析构函数)** – A special member function with the same name as the class prefixed by `~` (如`~Player()`), called automatically when an object is destroyed (对象生命周期结束时调用). The destructor’s role is to free resources that the object may have acquired (like memory, file handles) before the object is removed from memory. Key properties: + + - A class **has at most one destructor** (no overloading for destructors, no parameters, no return type). If you don’t define one, the compiler generates a default destructor that simply calls destructors of data members (for class members) and does nothing special. + - Destructors are called automatically in the reverse order of construction (构造相反顺序) when objects go out of scope or are explicitly deleted. For example, in stack unwinding, local objects are destroyed in the opposite order of their creation. + - If an object is created with `new`, its destructor is called when you `delete` that object. If created as a local (stack) object, destructor called at end of scope. For global/static objects, destructors called when program terminates (in unspecified order across translation units). + - If `exit()` or `abort()` is called, destructors of some objects may not execute (especially `abort()` kills program without cleanup). + - **Important for memory management**: If your class allocates dynamic memory (via `new`), define a destructor to `delete` that memory to avoid leaks (or better use smart pointers to manage automatically). In classes that follow RAII (Resource Acquisition Is Initialization), the destructor releases the resource. Example: a file wrapper class closes the file in its destructor. + *(Java has no direct destructor concept; Java uses garbage collection. For cleanup (like closing files), Java relies on `finally` blocks or try-with-resources, or overriding `finalize()` (which is deprecated in Java 9+). Finalize is not deterministic and not recommended. In contrast, C++ destructors are deterministic and key to resource management.* + +- **Constructor and Destructor Call Order(构造和析构的顺序)** – For automatic objects (栈对象), constructors execute when entering their scope, destructors when leaving scope (like end of function or block). When multiple objects exist: + + - If objects are defined in sequence, they are constructed in that sequence and destructed in reverse sequence (后创建的先析构). + - For class composition (对象成员): Member objects are constructed before the enclosing class’s constructor body executes (in order of their declaration in the class) and destructed after the class’s destructor body executes (in reverse order). + - For inheritance: Base class constructor runs before derived class constructor, and base destructor runs after derived destructor (base part is last constructed, first destroyed since derived “contains” base). + - **Global and static objects**: constructed before `main` begins (order across translation units not strictly defined), destructed after `main` exits (order is reverse of construction within each translation unit). + - If `exit()` is used, static objects might not destruct properly; if `abort()` used, none will. + - In summary: 构造函数调用按声明/继承顺序向内深入,析构函数调用按相反顺序向外展开。 + +- **Const Objects and const Member Functions(常量对象与常量成员函数)** – If you declare an object as `const` (如`const Player p;`), it cannot be modified. In particular, you can only call that object’s **const member functions(常量成员函数)**. A member function is made const by adding `const` after its parameter list, both in prototype and definition. For example, + + ```cpp + class Player { + public: + string getName() const { return name; } + void setName(string n) { name = n; } + private: + string name; + }; + ``` + + Here `getName()` is a const member function – it promises not to modify the object (编译器会强制保证函数体内不修改成员变量). You can call `getName()` on a const Player, but cannot call `setName()` because that function isn’t marked const. Const correctness helps catch unintended modifications and allows usage of objects in read-only context (like passing a const reference to a function to ensure it doesn’t modify the argument). *Java does not have const methods or const objects. Instead, immutability in Java is a design choice (like making fields private and not providing setters, or using `final` for fields, but there’s no language-enforced const for methods or objects). C++ const is a compile-time check to prevent modification through that interface.* + +- **Composition(组合)** – A class can have members that are objects of other classes (class A has a member of class B type). This is called a “has-a” relationship or composition (合成关系:一个类拥有另一个类的对象). For example, a `Car` class might have an `Engine` object as a member. Composition implies that the lifetime of the part (成员对象) is tied to the whole: when the Car is constructed, its Engine member is constructed; when Car is destroyed, Engine is destroyed. It’s a way to reuse classes by building complex ones from simpler ones (Car由Engine, Wheel等部件组成). *(Java also has object references as fields to achieve composition, with similar semantics aside from memory allocation differences. In Java, an object field is a reference that could be null or refer to a shared object; in C++ if you have an object member (not pointer), it’s embedded and cannot be null – it always exists as part of the containing object.)* + +- **Friend Functions and Friend Classes(友元函数与友元类)** – The `friend` keyword allows a non-member function or another class to access the private/protected members of a class. This is an exception to the usual encapsulation rules. For example: + + ```cpp + class MyClass { + friend void secretFunction(MyClass& obj); + friend class MyFriend; + private: + int secretData; + }; + ``` + + Here `secretFunction` and all members of `MyFriend` class can access `MyClass::secretData` directly. Friendship is granted, not taken: it must be declared within the class that is giving access. It’s neither symmetric nor transitive: if A is friend of B, B is not automatically friend of A; if A is friend of B and B is friend of C, A is not friend of C. **Use cases:** sometimes needed for operator overloading (to allow an external function to access privates) or if two classes need intimate access to each other’s internals. But overuse of `friend` can break encapsulation and make maintenance harder, so use sparingly. *(Java has no friend concept. Java achieves similar trust through package-private access (classes in the same package can access each other’s package-private members) or simply making members public. But there's no direct way to allow one specific external function/class access without making things globally accessible, short of nested classes. C++ friend is a targeted relaxation of access control.)* + +- **`this` Pointer(this指针)** – Inside a non-static member function, `this` is a pointer to the object on which the function was invoked. It has type `ClassName* const` (a const pointer to the object). You can use `this` to refer to the object’s members (especially if names are shadowed) or to return the object itself (like in operator overloading chaining). In a const member function, `this` is of type `const ClassName*`. Java similarly has a `this` reference inside instance methods, though it’s used less explicitly (commonly only for disambiguating field names or passing the current object as parameter). In C++ you often see patterns like `return *this;` in methods to allow chaining. + +- **Static Class Members(静态类成员)** – C++ classes can have **static data members(静态数据成员)** and **static member functions(静态成员函数)**. A static data member is essentially a global variable that is scoped to the class (所有对象共享的类级变量). It exists independently of any object instances (即使没有创建对象,静态成员也存在并可访问). You define it *outside* the class as well (one definition in a .cpp): e.g., `int MyClass::count = 0;` to allocate it. Use cases: class-wide information, like a counter of how many objects have been created (each constructor increments, destructor decrements). Static member functions are functions not tied to a specific object (no `this` pointer inside). They can only access static members (because there’s no object context). Call static members with class name: `MyClass::count` or `MyClass::staticFunc()`. *(Java’s `static` fields and methods are analogous. The main difference: C++ static data members need to be defined in one .cpp file, whereas Java static fields are defined in the class itself at declaration. Also, C++ has no direct equivalent of Java’s static initializer blocks, but you can assign initial values in the definition or use static constructors in modern C++17 (inline static initializations).)* + + - If you want to call a static function or use a static data without any objects, you can do so. E.g., a class `MathUtils` could have `static double PI; static double square(double x);` and you use `MathUtils::PI` or `MathUtils::square(5.0)` directly (like Java’s `Math.PI` and `Math.sqrt()`). + - Static data members are initialized to 0 (for fundamental types) by default if not explicitly initialized. They live in static storage (like global variables). + - A common pattern is **singleton**: a class with a private static instance of itself and a static method to get that instance. + - Remember to define static data in one translation unit or mark it `inline` (C++17) to avoid multiple definitions error. + +- **Member Initializer List(成员初始值列表)** – A syntax used in constructor definitions to initialize data members (especially important for const and reference members which **must** be initialized, not assigned). For example: + + ```cpp + class Example { + const int size; + int * data; + public: + Example(int s): size(s), data(new int[s]) { /*...*/ } + }; + ``` + + The part `: size(s), data(new int[s])` is the initializer list. It initializes `size` and `data` **before** the constructor body runs. Benefits: + + - Efficiency: avoid default-constructing then assigning. For complex members, initialization can be faster than default construct + assignment (especially for objects of classes as members). + - Necessity: const and reference members cannot be assigned in constructor body; they must be initialized in the initializer list. Static data members cannot be initialized in the initializer list (they’re handled separately at definition). + - Order: Members are initialized in the order of their declaration in the class, not the order in the initializer list. It’s wise to list them in same order to avoid confusion. + *(Java has no equivalent because instance fields can be assigned in body or an init block, but effectively Java does initialization before constructor body too, except you don’t control the order beyond writing them in code order. Java final fields must be assigned by constructor completion but you usually just do it in constructor body or inline initializers, no special syntax needed.)* + +**After-class Exercises 课后练习:** + +1. **填空题:** 若要允许一个非成员函数访问类的私有成员,可以在类定义中将该函数声明为 ______ 函数。【提示】声明为该类的**友元(friend)**函数。 +2. **填空题:** 对象的非静态成员函数可以通过一个隐含的“自我指针”访问所属对象,该指针称为 ______ 指针。【提示】称为`this`指针。 + +*(Lecture 8 slides did not explicitly list many exercise questions beyond friend and this pointer fill-in, so we focus on those.)* + +**Suggested Answers 答案:** 1) **友元**函数; 2) **this**指针。请注意,`friend`关键字可以使指定的函数或类突破封装直接访问私有成员,但应谨慎使用。`this`指针在C++中是隐含参数,用于指向调用该成员函数的对象地址,在需要时可显式使用,如返回`*this`实现链式调用。 + +## Lecture 9: Operator Overloading (第9讲:运算符重载) + +**Key Concepts 主要知识点:** + +- **Operator Overloading(运算符重载)** – C++ allows giving operators like `+`, `-`, `==`, `<<`, etc., custom meanings for user-defined types (为用户自定义类型定义运算符功能). This enhances expressiveness – e.g., you can use `a + b` for two complex numbers or concatenate two strings with `+` if you define it. In C++, most operators can be overloaded except a few (notably `.` member access, `.*` pointer-to-member, `::` scope resolution, `?:` ternary, and `sizeof` cannot be overloaded). To overload an operator, you define a function with special name `operatorX` where X is the operator symbol. For example: + + ```cpp + class Complex { + public: + Complex operator+(const Complex& rhs) const { + return Complex(real + rhs.real, imag + rhs.imag); + } + }; + ``` + + This overloads `+` for Complex addition. Then `c1 + c2` calls this function (as a member function on `c1` with argument `c2`). Some operators are best overloaded as member functions (like assignment `operator=` must be member) and some as friend or free functions (like `operator<<` for streams, since left operand isn’t a class object but an `ostream`). + + - **Syntax**: If a binary operator is overloaded as a member, it takes one parameter (the right-hand side). If as a free function, it takes two parameters (left and right). For symmetric operations, free function can be friend for access. + + - **Rules**: You cannot change operator precedence or associativity, and you cannot create new operators – only overload existing ones. The overloaded operator’s arity (unary/binary) and meaning should be intuitive. + + - **Example**: Overloading `<<` for output: + + ```cpp + std::ostream& operator<<(std::ostream& os, const Complex& c) { + return os << c.real << "+" << c.imag << "i"; + } + ``` + + This allows `cout << complexObj;` to print a Complex. Usually `operator<<` is a non-member (cannot be member of std::ostream or Complex), hence made a friend of Complex to access privates. + + - **Operator=**: If you define custom copy semantics, overload assignment operator. If not, C++ provides a default member-wise copy assignment. Similarly, you can overload `operator==` to compare objects meaningfully (default does bitwise compare? Actually default `==` not generated, must overload for user types). + +- **Conversion Operators(类型转换运算符)** – You can define `operator type()` in a class to convert an object to another type implicitly. E.g., `operator int() const { return value; }` in a class would allow an object to be used where int is expected. Use carefully – implicit conversions can introduce ambiguities or unexpected results. (In Java, you can’t overload casting or define implicit conversions; you must use explicit methods). + +- **Explicit Keyword** – In C++11 and above, you can mark single-parameter constructors as `explicit` to avoid them being used as implicit conversions. Similarly, conversion operators can be marked explicit (C++20) to require explicit cast. This prevents unintended conversions. (Java doesn’t have an equivalent since no user-defined implicit conversions exist.) + +- **Overloading vs Overriding** – Operator overloading is about same operator symbol working on different types (ad-hoc polymorphism). It’s resolved at compile time by checking operand types. This is different from overriding virtual functions (runtime polymorphism, Lecture 11). (Java doesn’t have operator overloading at all, so less confusion there; C++ needs careful distinction between overload vs override – hence `override` keyword introduced for clarity in virtual functions override). + +**After-class Exercises 课后练习:** + +1. **填空题:** 要重载一元或二元运算符,需要定义一个名为 ______ 的函数。【提示】函数名形式为`operator+`、`operator==`等,例如重载`+`则函数名为`operator+`。 +2. **判断题:** 运算符重载可以改变运算符的优先级从而影响表达式求值顺序。(对/错)【提示】**错。**重载运算符不会改变其既定的优先级和结合性,表达式求值规则保持不变。 +3. **判断题:** Java允许用户为自定义类重载运算符。(对/错)【提示】**错。**Java不支持运算符重载,除了`+`用于字符串连接是语言内置特例外,其他运算符不可重定义。 + +*Answers 答案:* 1) 形如`operator+`的函数名(以`operator`加运算符符号命名); 2) 错;3) 错。请记住,C++运算符重载应遵循直观原则,例如`operator+`应实现类似“加法”的语义。不能重载的新运算符包括`.`、`::`、`?:`等。而在Java中运算符重载不可用,只能通过定义方法实现类似功能(例如用`add()`方法代替重载`+`号)。 + +## Lecture 10: Inheritance (Extending Classes) (第10讲:继承 – 扩展类) + +**Key Concepts 主要知识点:** + +- **Inheritance(继承)** – A mechanism for creating a new class (子类/派生类) from an existing class (基类/父类), absorbing its attributes and behaviors and optionally adding new features or overriding existing ones. In C++, class inheritance is specified with a **colon and access specifier**. Example: `class Student : public Person { ... };` means Student **inherits publicly from** Person (Student *is-a* Person). Key points: + + - The derived class automatically has the data members and member functions of the base class (though private members of base are not accessible directly in derived, they are present but hidden). Public and protected base members become part of the derived class interface (public stays public, protected stays protected if using public inheritance). + - **Access specifier (public/protected/private) in inheritance**: This determines how the base’s public/protected members are treated in derived. + - **Public Inheritance 公有继承**: The most common form. Base class’s public members remain public in derived, protected remain protected. This models an “is-a” relationship: a Student is a Person, so it should be usable wherever a Person is expected (Liskov Substitution Principle). + - **Protected Inheritance 受保护继承**: Base public and protected become protected in derived. Not common; essentially, you don’t want outside code to treat the derived as the base type. + - **Private Inheritance 私有继承**: Base public and protected become private in derived. It’s more of a composition (“implemented in terms of”) than an is-a; not polymorphic. Rarely used except in certain design patterns or when you want to hide base interface. + *(Java only has a concept similar to public inheritance. All Java classes extend a base (explicit or `Object` implicitly), and all public/protected remain accessible in subclass. Java doesn’t allow changing the access level of inherited members except you cannot reduce visibility of an overridden method.)* + - **Single vs Multiple Inheritance**: C++ supports multiple inheritance (一个子类可同时继承多个基类). Syntax: `class C : public A, public B { ... };`. This can lead to complexities like **diamond problem** if both A and B inherit from a common base (C++ resolves with virtual inheritance if needed). Java forbids multiple class inheritance; it allows multiple interfaces instead (interfaces are like pure abstract base classes). + - **Inheritance Hierarchies(继承层次)**: Classes can be derived multiple levels (子类的子类, etc.). At the root, often an abstract base class (see polymorphism in Lecture 11). + - Use inheritance when there is a clear generalization-specialization relationship (一般和特殊的关系). For example, `Person` as base, `Student` and `Teacher` as derived, sharing common attributes of Person but adding their own. + +- **Protected Members(保护成员)** – In C++, `protected` access means the member is accessible within the class and its derived classes (and also within the same module as friend or within same class scope). Protected is a way to allow subclasses to use base internals but keep them hidden from outside world. In Java, `protected` means accessible to subclasses *and* also to classes in the same package. C++ has no package concept, so protected is strictly subclass access (plus friend). Protected is useful when you want an inheritor to have some degree of access for convenience, but you don’t want the general user (via a base class reference) to access those members. + +- **Base and Derived Constructors(基类与派生类构造)** – When you instantiate a derived class object, the **base class constructor runs first** to initialize the base part of the object, then the derived class’s constructor runs. The derived constructor can call a specific base class constructor using an initializer list: + + ```cpp + class Student : public Person { + public: + Student(string name, int gradYear) : Person(name), graduationYear(gradYear) { } + ... + }; + ``` + + If a base constructor requires arguments, you *must* call it explicitly in the initializer list. If you don’t call any, C++ tries to call the base’s default constructor implicitly. Similarly, **destructors** execute in reverse: first the derived’s destructor, then the base’s destructor. This ensures proper construction/destruction chain. *(Java automatically calls the base class constructor (no syntax for choosing base constructor except via `super()` call as first line in subclass constructor). If you don’t call `super(...)` explicitly, Java inserts a call to the no-arg super constructor. C++ similarly calls default base ctor if not specified.)* + +- **Overriding and Hiding(重写与隐藏)** – If a derived class defines a method with the same signature as a base class **virtual** method, it **overrides(重写)** that method (when called through a base pointer/reference, the derived version is used at runtime – see Lecture 11 on polymorphism). If the base method is not virtual (just a normal function), then defining a same name in derived results in **hiding** (also called shadowing) – which is not polymorphic; it simply means if you call that function on a derived object (statically typed as derived), you get the derived version, but if you call it on base or through a base pointer, you get base version because static binding. To override properly, the base function should be virtual. + + - C++11 introduced the `override` keyword to explicitly mark overriding functions; the compiler will error if it doesn’t actually override a base virtual. Use this to avoid mistakes (accidental signature mismatch). Java by default treats all non-final instance methods as virtual and overrides them if signatures match in subclass. Java’s `@Override` annotation is like C++ `override` to catch errors. + - Also note: In C++, if you overload a function name in derived with a different signature, it *hides* all base class functions of the same name (even those with different signatures) from the scope. You can bring them in with `using Base::functionName;` if needed. Java doesn’t have this exact issue because name resolution is always at compile-time by full signature, and methods with different sig are simply overloads existing in class. C++ name hiding is a quirk due to separate compilation and might require `using` to fix. + +- **Multiple Inheritance and Virtual Base Classes(多重继承与虚基类)** – If a class inherits from two classes that have a common base, the default is you get two copies of that base in the derived object (ambiguity which one to use). C++ allows **virtual inheritance** to solve the diamond problem, so the common base is shared (one subobject). Syntax: `class MyClass : virtual public BaseClass { ... };`. Virtual inheritance ensures only one base subobject even if base appears multiple times in hierarchy. This is advanced and only needed in certain MI scenarios. Java’s way to avoid diamond is by not allowing multiple inheritance of classes at all (interfaces don’t have state so diamond doesn’t cause state duplication). + +- **Polymorphism preview** – (Though more in Lecture 11) Under inheritance, a derived object can be treated as a base object. You can assign a `Derived*` to a `Base*` (implicit upcast), or call a function expecting a Base reference with a Derived object. This is core to substitutability. If the function is virtual, the derived override will execute (if polymorphism is set up). If not virtual, base version executes (static binding). Non-polymorphic inheritance is essentially reuse of code without runtime flexibility. + +**After-class Exercises 课后练习:** + +1. **判断题:** 在公有继承下,基类的`public`成员在派生类中变为`private`。(对/错)【提示】**错。**公有继承不会降低可见性,基类public成员在派生类中仍为public;protected成员在派生类中仍为protected。只有`private`继承才会将基类的public和protected成员变为private。 +2. **判断题:** C++允许一个类同时继承自多个基类。(对/错)【提示】**对。**C++支持多重继承,一个派生类可有多个直接基类。但要注意可能出现“菱形继承”问题,需要虚继承解决。Java不支持类的多继承。 +3. **判断题:** 可以使用基类类型的指针或引用指向派生类对象。(对/错)【提示】**对。\**派生类对象\**是**一种基类对象,因此基类指针/引用可指向派生对象(向上转型),这实现了多态的基础。通过基类指针调用虚函数会执行派生类覆写的版本(见Lecture 11)。 + +*Answers 答案:* 1) 错;2) 对;3) 对。请注意,在使用基类指针指向派生对象时,若调用非虚函数,则只会执行基类实现(静态绑定);只有虚函数才会多态地调用派生实现。良好的面向对象设计在继承层次中运用`public`继承表示”is-a”关系,并尽量避免使用`protected`或`private`继承。此外,尽管C++允许多继承,但设计时需谨慎,Java通过接口解决多继承需求,这在C++中也可以用组合(composition)或虚继承达到类似目的。 + +## Lecture 11: Polymorphism and Virtual Functions (第11讲:多态与虚函数) + +**Key Concepts 主要知识点:** + +- **Polymorphism(多态)** – Literally "many forms". In OOP, it refers to the ability to treat objects of different derived classes through a common base class interface, and have the correct overridden functions called according to the actual object type at runtime. Polymorphism enables you to **“program in the general rather than the specific”(面向抽象编程,而非面向具体实现)**. The primary mechanism for polymorphism in C++ is **virtual functions(虚函数)**. + + - Polymorphism lets you write code that works on base class pointers/references but actually processes derived class objects. For example, you might have a `Shape` base class with a virtual `draw()` method, and derived classes `Circle`, `Square` override `draw()`. If you store various shapes in an array of `Shape*` and call `draw()` on each, the appropriate derived class implementation executes (circle draws a circle, square draws a square). + - This relies on late binding (动态绑定): the decision of which function body to execute is made at runtime based on the actual object type, not at compile time (静态类型是基类,但对象实际类型是子类). Without virtual, C++ would do early binding (静态绑定) and call the base version always when using base pointer. + - Polymorphism usually goes hand in hand with **inheritance(继承)** and **virtual functions**. + +- **Virtual Functions(虚函数)** – Declared with keyword `virtual` in the base class, these functions are intended to be overridden in derived classes. A virtual function call is resolved dynamically at runtime via the **vtable(虚函数表)** mechanism. For example: + + ```cpp + class Base { + public: virtual void foo() { cout<<"Base"; } + }; + class Derived : public Base { + public: void foo() override { cout<<"Derived"; } + }; + ``` + + Now, `Base* p = new Derived(); p->foo();` will print "Derived" because `foo` is virtual. If `foo` were not virtual, it would print "Base" (static binding). + + - To override a virtual function in C++, the signature must match exactly (aside from `override` or covariant return). Marking the override with `override` (optional but recommended C++11) helps catch errors. + - **Pure Virtual Functions(纯虚函数)**: `virtual void foo() = 0;` in a class makes it abstract – no implementation in base, derived classes must override it to be concrete. A class with any pure virtual is an **abstract class(抽象类)**, cannot be instantiated. This is similar to Java’s abstract methods and abstract classes. Pure virtual functions allow defining an interface that derived classes must implement. + - Virtual functions can be overridden to provide specialized behavior in subclasses. If a subclass does not override a virtual, it inherits base’s implementation. You can call base class version from derived if needed (explicitly `Base::foo();`). + - If a derived class fails to override a pure virtual, that derived remains abstract. All concrete (非抽象) derived classes must override all base class pure virtuals. + - **Virtual Destructor**: If a class is meant to be a base class (especially if delete via base pointer is possible), declare a virtual destructor. This ensures that deleting a derived object through a base pointer calls the derived’s destructor fully. In polymorphic base classes, the destructor should be virtual to avoid resource leaks. (Java has GC, so no concept of destructors; all objects properly finalize when collected. But if Java had manual deletion, their Object class’s finalize is akin but not the same. C++ requires explicit management). + +- **Dynamic Binding and Vtable(动态绑定与虚函数表)** – At runtime, polymorphic objects carry a pointer to a vtable (a table of function pointers for virtual functions). When you call a virtual function, it uses the vtable of the actual object’s class to jump to the right function. This indirection is why calls through base pointers go to derived overrides. Implementation detail: typically the first element of an object of a class with virtual functions is a vptr (虚指针) pointing to the table. (Java’s method dispatch is similar in concept; all non-static, non-final methods in Java use a vtable-like mechanism for dynamic dispatch). The cost is one pointer dereference; negligible in most cases. + +- **Polymorphic Interface and Extensibility** – Polymorphism allows writing code that doesn’t need to know exact subclasses in advance. For example, a function `printShapeArea(Shape& s)` can call `s.area()` and get correct result for Circle, Square, etc., without separate code for each. Adding new Shape types (Triangle, etc.) doesn’t require changing `printShapeArea` – it’s **extensible(易扩展)**. This is the Open-Closed Principle: modules open for extension (via new subclasses) but closed for modification. Polymorphism in C++ and Java achieves that. + +- **Upcasting and Downcasting(向上转型与向下转型)** – **Upcasting** is converting a derived object reference/pointer to a base type (安全且隐式进行). This is how we store derived in base pointer for polymorphism. **Downcasting** is converting base reference/pointer to a derived type. In C++, use `dynamic_cast(basePtr)` for a safe downcast (it returns nullptr if object isn’t actually a `Derived`). This requires the base class to have at least one virtual function (so it has RTTI info). In Java, downcast uses `(Derived) baseRef`, which throws `ClassCastException` if the object isn’t that type. The logic is similar: check actual type at runtime. If downcasting, ensure the object is indeed that subclass (via `dynamic_cast` or other means). Minimizing downcasts is often a design goal (rather use polymorphic virtual calls). + + - **`typeid` and RTTI**: C++ provides `typeid` to get type info at runtime (for polymorphic types yields actual type). Java has `instanceof` or `getClass()`. + - If you find you need to downcast often, consider if virtual functions could handle the variation instead (polymorphism intended to reduce explicit type checking). + +- **Abstract Base Classes(抽象基类)** – A class with one or more pure virtual functions. It serves as an interface (perhaps partial implementation) that cannot be instantiated. Only concrete subclasses (classes implementing all pure virtuals) can be instantiated. Abstract classes in C++ correspond to abstract classes in Java (with abstract methods). They allow defining interfaces. For example, an abstract `Shape` with pure virtual `draw()` and `area()`, implemented by concrete `Circle`, `Rectangle`, etc. Attempting to create a `Shape` object would be a compile error (just like `new Shape()` illegal in Java if Shape is abstract). + +- **Virtual Inheritance of Destructors** – Emphasizing: if a class is meant to be base class (polymorphic), declare virtual destructor. If not, deleting derived via base pointer is undefined (the base destructor will run but not the derived’s portion). Polymorphic base classes typically have at least one virtual, so destructor should be virtual as well. (Java doesn’t have this issue because all objects are tracked by GC; you don’t manually delete and all parts get collected.) + +**After-class Exercises 课后练习:** + +1. **判断题:** 若基类的成员函数被声明为虚函数,则通过基类指针调用派生类对象的该函数时,会执行派生类版本。(对/错)【提示】**对。**虚函数调用会在运行时绑定到对象实际类型的实现。如果没有将其声明为virtual,则不会发生多态。 +2. **判断题:** 含有纯虚函数的类是抽象类,不能直接创建对象。(对/错)【提示】**对。**抽象类必须被继承并实现纯虚函数才能实例化对象。 +3. **判断题:** 通过基类指针删除派生类对象时,应确保基类析构函数为虚函数,否则可能导致资源未正确释放。(对/错)【提示】**对。**基类析构应为virtual,以便delete时调用派生类析构函数。否则行为未定义,通常会导致只执行基类析构,派生部分没释放,造成内存泄漏或错误。 +4. **填空题:** 要求所有派生类必须覆写某函数,可将该函数在基类中声明为 ______ 。【提示】将函数定义为纯虚函数(pure virtual),语法是在函数声明末尾加`=0`。 +5. **填空题:** C++中,将`Base*`指针安全地转换为指向其派生类型对象的指针,应该使用的运算符是 ______ 。【提示】使用运行时类型识别的`dynamic_cast`。例如`dynamic_cast(basePtr)`。 + +*参考答案:* 1) 对; 2) 对; 3) 对; 4) **纯虚函数**; 5) **dynamic_cast**。以上强调:**多态**让我们可以通过基类接口操作不同派生类对象,并自动调用恰当的实现。在设计类层次时,基类应尽可能将接口函数声明为virtual,并在需要强制子类实现时使用纯虚函数将类抽象化。另一方面,如果类不打算作为基类使用,则无需将析构函数声明为虚的,这样略微减少虚表开销。Java程序员转到C++需特别注意虚函数的声明和`override`关键字的使用,以避免逻辑错误。另外,在需要判断对象实际类型时,C++的`dynamic_cast`相当于Java的强制类型转换加`instanceof`检查,它返回nullptr表示类型不匹配,而Java则抛出异常。通过合理使用多态,可极大提高代码的扩展性和可维护性。 \ No newline at end of file diff --git a/山东理工大学/其他/前端.md b/山东理工大学/其他/前端.md new file mode 100644 index 0000000..bd725b3 --- /dev/null +++ b/山东理工大学/其他/前端.md @@ -0,0 +1,32 @@ +## BOM broswer + +学习的是window 的属性以及window的API + +```html + + + + + + + + + + + +``` + ++ 效果 + +jingxi + + + +> 外部脚本方式引入 + ++ 说明 + + 内部脚本仅能在当前页面上使用,代码复用度不高 + + 可以将脚本放在独立的js文件中,通过script标签引入外部脚本文件 + + 一对script标签要么用于定义内部脚本,要么用于引入外部js文件,不能混用 + + 一个html文档中,可以有多个script标签 ++ 抽取脚本代码到独立的js文件中 + +1681270974917 + ++ 在html文件中,通过script标签引入外部脚本文件 + +``` html + + + + + 小标题 + + + + + + + + +``` + +# 二 JS的数据类型和运算符 + +## 2.1 JS的数据类型 + +> 数值类型 + ++ 数值类型统一为 number,不区分整数和浮点数 + +> 字符串类型 + ++ 字符串类型为 string 和JAVA中的String相似,JS中不严格区分单双引号,都可以用于表示字符串 + +> 布尔类型 + ++ 布尔类型为boolean 和Java中的boolean相似,但是在JS的if语句中,非空字符串会被转换为'真',非零数字也会被认为是'真' + +> 引用数据类型 + ++ 引用数据类型对象是Object类型, 各种对象和数组在JS中都是Object类型 + +> function类型 + ++ JS中的各种函数属于function数据类型 + +> 命名未赋值 + ++ js为弱类型语言,统一使用 var 声明对象和变量,在赋值时才确定真正的数据类型,变量如果只声明没有赋值的话,数据类型为undefined + +> 赋予NULL值 + ++ 在JS中,如果给一个变量赋值为null,其数据类型是Object, 可以通过typeof关键字判断数据类型 + +## 2.2 JS的变量 + +> JS中的变量具有如下特征 + ++ 1 弱类型变量,可以统一声明成var ++ 2 var声明的变量可以再次声明 ++ 3 变量可以使用不同的数据类型多次赋值 ++ 4 JS的语句可以以; 结尾,也可以不用;结尾 ++ 5 变量标识符严格区分大小写 ++ 6 标识符的命名规则参照JAVA ++ 7 如果使用了 一个没有声明的变量,那么运行时会报uncaught ReferenceError: *** is not defined at index.html:行号:列号 ++ 8 如果一个变量只声明,没赋值,那么值是undefined + +## 2.3 JS的运算符 + +> 算数运算符 + - * / % + ++ 其中需要注意的是 / 和 % + + / 在除0时,结果是Infinity ,而不是报错 + + %在模0时,结果是NaN,意思为 not a number ,而不是报错 + +> 复合算数运算符 ++ -- += -= *= /= %= + ++ 符合算数运算符基本和JAVA一致,同样需要注意 /=和%= + + 在/=0时,结果是Infinity ,而不是报错 + + 在%=0时,结果是NaN,意思为 not a number ,而不是报错 + +> 关系运算符 > < >= <= == === != + ++ 需要注意的是 == 和 === 差别 + + == 符号,如果两端的数据类型不一致,会尝试将两端的数据转换成number,再对比number大小 + + '123' 这种字符串可以转换成数字 + + true会被转换成1 false会被转换成0 + + === 符号,如果两端数据类型不一致,直接返回false,数据类型一致在比较是否相同 + +> 逻辑运算符 || && + ++ 几乎和JAVA中的一样,需要注意的是,这里直接就是短路的逻辑运算符,单个的 | 和 & 以及 ^ 是位运算符 + +> 条件运算符 条件? 值1 : 值2 + ++ 几乎和JAVA中的一样 + +> 位运算符 | & ^ << >> >>> + ++ 和 java中的类似(了解) + +# 三 JS的流程控制和函数 + +## 3.1 JS分支结构 + +> if结构 + ++ 这里的if结构几乎和JAVA中的一样,需要注意的是 + + if()中的非空字符串会被认为是true + + if()中的非零数字会被认为是true + ++ 代码 + +``` javascript +if('false'){// 非空字符串 if判断为true + console.log(true) +}else{ + console.log(false) +} +if(''){// 长度为0字符串 if判断为false + console.log(true) +}else{ + console.log(false) +} +if(1){// 非零数字 if判断为true + console.log(true) +}else{ + console.log(false) +} +if(0){ + console.log(true) +}else{ + console.log(false) +} +``` + ++ 结果 + +![1681285904625](images/1681285904625.png) + +> switch结构 + ++ 几乎和JAVA的语法一致 + ++ 代码 + +``` javascript +var monthStr=prompt("请输入月份","例如:10 "); +var month= Number.parseInt(monthStr) +switch(month){ + case 3: + case 4: + case 5: + console.log("春季"); + break; + case 6: + case 7: + case 8: + console.log("夏季"); + break; + case 9: + case 10: + case 11: + console.log("秋季"); + break; + case 1: + case 2: + case 12: + console.log("冬季"); + break; + default : + console.log("月份有误") +} +``` + ++ 效果 + +switchex + + + +## 3.2 JS循环结构 + +> while结构 + ++ 几乎和JAVA一致 + ++ 代码 + +``` javascript +/* 打印99 乘法表 */ +var i = 1; +while(i <= 9){ + var j = 1; + while(j <= i){ + document.write(j+"*"+i+"="+i*j+"     "); + j++; + } + document.write("
"); + i++; +} +``` + ++ 效果 + +1681287264843 + +> for循环 + ++ 几乎和JAVA一致 + ++ 代码 + +``` javascript +/* 打印99 乘法表 */ +for( var i = 1;i <= 9; i++){ + for(var j = 1;j <= i;j++){ + document.write(j+"*"+i+"="+i*j+"     "); + } + document.write("
"); +} +``` + ++ 效果 + +1681287264843 + +> foreach循环 + ++ 迭代数组时,和java不一样 + + 括号中的临时变量表示的是元素的索引,不是元素的值, + + ()中也不在使用: 分隔,而是使用 in 关键字 + ++ 代码 + +``` javascript +var cities =["北京","上海","深圳","武汉","西安","成都"] +document.write("
    ") +for(var index in cities){ + document.write("
  • "+cities[index]+"
  • ") +} +document.write("
") +``` + ++ 效果 + +![1681287540562](images/1681287540562.png) + +## 3.3 JS函数声明 + +> JS中的方法,多称为函数,函数的声明语法和JAVA中有较大区别 + ++ 函数说明 + + 函数没有权限控制符 + + 不用声明函数的返回值类型,需要返回在函数体中直接return即可,也无需void关键字 + + 参数列表中,无需数据类型 + + 调用函数时,实参和形参的个数可以不一致 + + 声明函数时需要用function关键字 + + J函数没有异常列表 ++ 代码 + +``` javascript +/* +语法1 + function 函数名 (参数列表){函数体} + */ +function sum(a, b){ + return a+b; +} +var result =sum(10,20); +console.log(result) + +/* +语法2 + var 函数名 = function (参数列表){函数体} + */ +var add = function(a, b){ + return a+b; +} +var result = add(1,2); +console.log(result); +``` + ++ 调用测试 + +![1681287984473](images/1681287984473.png) + + + +# 四 JS的对象和JSON + +## 4.1 JS声明对象的语法 + +> 语法1 通过new Object()直接创建对象 + ++ 代码 + +```javascript +var person =new Object(); +// 给对象添加属性并赋值 +person.name="张小明"; +person.age=10; +person.foods=["苹果","橘子","香蕉","葡萄"]; +// 给对象添加功能函数 +person.eat= function (){ + console.log(this.age+"岁的"+this.name+"喜欢吃:") + for(var i = 0;i 语法2 通过 {}形式创建对象 + ++ 语法为 var person ={"属性名":"属性值","属性名","属性值","函数名":函数} ++ 代码 + +``` javascript +var person ={ + "name":"张小明", + "age":10, + "foods":["苹果","香蕉","橘子","葡萄"], + "eat":function (){ + console.log(this.age+"岁的"+this.name+"喜欢吃:") + for(var i = 0;i JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率 简单来说,JSON 就是一种字符串格式,这种格式无论是在前端还是在后端,都可以很容易的转换成对象,所以常用于前后端数据传递 + ++ 说明 + + + JSON的语法 + + ​ var obj="{'属性名':'属性值','属性名':{'属性名':'属性值'},'属性名':['值1','值1','值3']}" + + + JSON字符串一般用于传递数据,所以字符串中的函数就显得没有意义,在此不做研究 + + + 通过JSON.parse()方法可以将一个JSON串转换成对象 + + + 通过JSON.stringify()方法可以将一个对象转换成一个JSON格式的字符串 + ++ 代码 + +``` javascript +/* 定义一个JSON串 */ +var personStr ='{"name":"张小明","age":20,"girlFriend":{"name":"铁铃","age":23},"foods":["苹果","香蕉","橘子","葡萄"],"pets":[{"petName":"大黄","petType":"dog"},{"petName":"小花","petType":"cat"}]}' +console.log(personStr) +console.log(typeof personStr) +/* 将一个JSON串转换为对象 */ +var person =JSON.parse(personStr); +console.log(person) +console.log(typeof person) +/* 获取对象属性值 */ +console.log(person.name) +console.log(person.age) +console.log(person.girlFriend.name) +console.log(person.foods[1]) +console.log(person.pets[1].petName) +console.log(person.pets[1].petType) +``` + + + +``` javascript +/* 定义一个对象 */ +var person={ + 'name':'张小明', + 'age':20, + 'girlFriend':{ + 'name':'铁铃', + 'age':23 + }, + 'foods':['苹果','香蕉','橘子','葡萄'], + 'pets':[ + { + 'petName':'大黄', + 'petType':'dog' + }, + { + 'petName':'小花', + 'petType':'cat' + } + ] +} + +/* 获取对象属性值 */ +console.log(person.name) +console.log(person.age) +console.log(person.girlFriend.name) +console.log(person.foods[1]) +console.log(person.pets[1].petName) +console.log(person.pets[1].petType) +/* 将对象转换成JSON字符串 */ +var personStr =JSON.stringify(person) +console.log(personStr) +console.log(typeof personStr) +``` + ++ 前后端传递数据 + +![1681292306466](images/1681292306466.png) + + + +## 4.3 JS常见对象 + +### 4.3.1 数组 + +> 创建数组的四种方式 + ++ new Array() 创建空数组 ++ new Array(5) 创建数组时给定长度 ++ new Array(ele1,ele2,ele3,... ... ,elen); 创建数组时指定元素值 ++ [ele1,ele2,ele3,... ... ,elen]; 相当于第三种语法的简写 + +> 数组的常见API + ++ 在JS中,数组属于Object类型,其长度是可以变化的,更像JAVA中的集合 + +| 方法 | 描述 | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| [concat()](https://www.runoob.com/jsref/jsref-concat-array.html) | 连接两个或更多的数组,并返回结果。 | +| [copyWithin()](https://www.runoob.com/jsref/jsref-copywithin.html) | 从数组的指定位置拷贝元素到数组的另一个指定位置中。 | +| [entries()](https://www.runoob.com/jsref/jsref-entries.html) | 返回数组的可迭代对象。 | +| [every()](https://www.runoob.com/jsref/jsref-every.html) | 检测数值元素的每个元素是否都符合条件。 | +| [fill()](https://www.runoob.com/jsref/jsref-fill.html) | 使用一个固定值来填充数组。 | +| [filter()](https://www.runoob.com/jsref/jsref-filter.html) | 检测数值元素,并返回符合条件所有元素的数组。 | +| [find()](https://www.runoob.com/jsref/jsref-find.html) | 返回符合传入测试(函数)条件的数组元素。 | +| [findIndex()](https://www.runoob.com/jsref/jsref-findindex.html) | 返回符合传入测试(函数)条件的数组元素索引。 | +| [forEach()](https://www.runoob.com/jsref/jsref-foreach.html) | 数组每个元素都执行一次回调函数。 | +| [from()](https://www.runoob.com/jsref/jsref-from.html) | 通过给定的对象中创建一个数组。 | +| [includes()](https://www.runoob.com/jsref/jsref-includes.html) | 判断一个数组是否包含一个指定的值。 | +| [indexOf()](https://www.runoob.com/jsref/jsref-indexof-array.html) | 搜索数组中的元素,并返回它所在的位置。 | +| [isArray()](https://www.runoob.com/jsref/jsref-isarray.html) | 判断对象是否为数组。 | +| [join()](https://www.runoob.com/jsref/jsref-join.html) | 把数组的所有元素放入一个字符串。 | +| [keys()](https://www.runoob.com/jsref/jsref-keys.html) | 返回数组的可迭代对象,包含原始数组的键(key)。 | +| [lastIndexOf()](https://www.runoob.com/jsref/jsref-lastindexof-array.html) | 搜索数组中的元素,并返回它最后出现的位置。 | +| [map()](https://www.runoob.com/jsref/jsref-map.html) | 通过指定函数处理数组的每个元素,并返回处理后的数组。 | +| [pop()](https://www.runoob.com/jsref/jsref-pop.html) | 删除数组的最后一个元素并返回删除的元素。 | +| [push()](https://www.runoob.com/jsref/jsref-push.html) | 向数组的末尾添加一个或更多元素,并返回新的长度。 | +| [reduce()](https://www.runoob.com/jsref/jsref-reduce.html) | 将数组元素计算为一个值(从左到右)。 | +| [reduceRight()](https://www.runoob.com/jsref/jsref-reduceright.html) | 将数组元素计算为一个值(从右到左)。 | +| [reverse()](https://www.runoob.com/jsref/jsref-reverse.html) | 反转数组的元素顺序。 | +| [shift()](https://www.runoob.com/jsref/jsref-shift.html) | 删除并返回数组的第一个元素。 | +| [slice()](https://www.runoob.com/jsref/jsref-slice-array.html) | 选取数组的一部分,并返回一个新数组。 | +| [some()](https://www.runoob.com/jsref/jsref-some.html) | 检测数组元素中是否有元素符合指定条件。 | +| [sort()](https://www.runoob.com/jsref/jsref-sort.html) | 对数组的元素进行排序。 | +| [splice()](https://www.runoob.com/jsref/jsref-splice.html) | 从数组中添加或删除元素。 | +| [toString()](https://www.runoob.com/jsref/jsref-tostring-array.html) | 把数组转换为字符串,并返回结果。 | +| [unshift()](https://www.runoob.com/jsref/jsref-unshift.html) | 向数组的开头添加一个或更多元素,并返回新的长度。 | +| [valueOf()](https://www.runoob.com/jsref/jsref-valueof-array.html) | 返回数组对象的原始值。 | +| [Array.of()](https://www.runoob.com/jsref/jsref-of-array.html) | 将一组值转换为数组。 | +| [Array.at()](https://www.runoob.com/jsref/jsref-at-array.html) | 用于接收一个整数值并返回该索引对应的元素,允许正数和负数。负整数从数组中的最后一个元素开始倒数。 | +| [Array.flat()](https://www.runoob.com/jsref/jsref-flat-array.html) | 创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。 | +| [Array.flatMap()](https://www.runoob.com/jsref/jsref-flatmap-array.html) | 使用映射函数映射每个元素,然后将结果压缩成一个新数组。 | + +### 4.3.2 Boolean对象 + +> boolean对象的方法比较简单 + +| 方法 | 描述 | +| :----------------------------------------------------------- | :--------------------------------- | +| [toString()](https://www.runoob.com/jsref/jsref-tostring-boolean.html) | 把布尔值转换为字符串,并返回结果。 | +| [valueOf()](https://www.runoob.com/jsref/jsref-valueof-boolean.html) | 返回 Boolean 对象的原始值。 | + +### 4.3.3 Date对象 + +> 和JAVA中的Date类比较类似 + +| 方法 | 描述 | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| [getDate()](https://www.runoob.com/jsref/jsref-getdate.html) | 从 Date 对象返回一个月中的某一天 (1 ~ 31)。 | +| [getDay()](https://www.runoob.com/jsref/jsref-getday.html) | 从 Date 对象返回一周中的某一天 (0 ~ 6)。 | +| [getFullYear()](https://www.runoob.com/jsref/jsref-getfullyear.html) | 从 Date 对象以四位数字返回年份。 | +| [getHours()](https://www.runoob.com/jsref/jsref-gethours.html) | 返回 Date 对象的小时 (0 ~ 23)。 | +| [getMilliseconds()](https://www.runoob.com/jsref/jsref-getmilliseconds.html) | 返回 Date 对象的毫秒(0 ~ 999)。 | +| [getMinutes()](https://www.runoob.com/jsref/jsref-getminutes.html) | 返回 Date 对象的分钟 (0 ~ 59)。 | +| [getMonth()](https://www.runoob.com/jsref/jsref-getmonth.html) | 从 Date 对象返回月份 (0 ~ 11)。 | +| [getSeconds()](https://www.runoob.com/jsref/jsref-getseconds.html) | 返回 Date 对象的秒数 (0 ~ 59)。 | +| [getTime()](https://www.runoob.com/jsref/jsref-gettime.html) | 返回 1970 年 1 月 1 日至今的毫秒数。 | +| [getTimezoneOffset()](https://www.runoob.com/jsref/jsref-gettimezoneoffset.html) | 返回本地时间与格林威治标准时间 (GMT) 的分钟差。 | +| [getUTCDate()](https://www.runoob.com/jsref/jsref-getutcdate.html) | 根据世界时从 Date 对象返回月中的一天 (1 ~ 31)。 | +| [getUTCDay()](https://www.runoob.com/jsref/jsref-getutcday.html) | 根据世界时从 Date 对象返回周中的一天 (0 ~ 6)。 | +| [getUTCFullYear()](https://www.runoob.com/jsref/jsref-getutcfullyear.html) | 根据世界时从 Date 对象返回四位数的年份。 | +| [getUTCHours()](https://www.runoob.com/jsref/jsref-getutchours.html) | 根据世界时返回 Date 对象的小时 (0 ~ 23)。 | +| [getUTCMilliseconds()](https://www.runoob.com/jsref/jsref-getutcmilliseconds.html) | 根据世界时返回 Date 对象的毫秒(0 ~ 999)。 | +| [getUTCMinutes()](https://www.runoob.com/jsref/jsref-getutcminutes.html) | 根据世界时返回 Date 对象的分钟 (0 ~ 59)。 | +| [getUTCMonth()](https://www.runoob.com/jsref/jsref-getutcmonth.html) | 根据世界时从 Date 对象返回月份 (0 ~ 11)。 | +| [getUTCSeconds()](https://www.runoob.com/jsref/jsref-getutcseconds.html) | 根据世界时返回 Date 对象的秒钟 (0 ~ 59)。 | +| getYear() | 已废弃。 请使用 getFullYear() 方法代替。 | +| [parse()](https://www.runoob.com/jsref/jsref-parse.html) | 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。 | +| [setDate()](https://www.runoob.com/jsref/jsref-setdate.html) | 设置 Date 对象中月的某一天 (1 ~ 31)。 | +| [setFullYear()](https://www.runoob.com/jsref/jsref-setfullyear.html) | 设置 Date 对象中的年份(四位数字)。 | +| [setHours()](https://www.runoob.com/jsref/jsref-sethours.html) | 设置 Date 对象中的小时 (0 ~ 23)。 | +| [setMilliseconds()](https://www.runoob.com/jsref/jsref-setmilliseconds.html) | 设置 Date 对象中的毫秒 (0 ~ 999)。 | +| [setMinutes()](https://www.runoob.com/jsref/jsref-setminutes.html) | 设置 Date 对象中的分钟 (0 ~ 59)。 | +| [setMonth()](https://www.runoob.com/jsref/jsref-setmonth.html) | 设置 Date 对象中月份 (0 ~ 11)。 | +| [setSeconds()](https://www.runoob.com/jsref/jsref-setseconds.html) | 设置 Date 对象中的秒钟 (0 ~ 59)。 | +| [setTime()](https://www.runoob.com/jsref/jsref-settime.html) | setTime() 方法以毫秒设置 Date 对象。 | +| [setUTCDate()](https://www.runoob.com/jsref/jsref-setutcdate.html) | 根据世界时设置 Date 对象中月份的一天 (1 ~ 31)。 | +| [setUTCFullYear()](https://www.runoob.com/jsref/jsref-setutcfullyear.html) | 根据世界时设置 Date 对象中的年份(四位数字)。 | +| [setUTCHours()](https://www.runoob.com/jsref/jsref-setutchours.html) | 根据世界时设置 Date 对象中的小时 (0 ~ 23)。 | +| [setUTCMilliseconds()](https://www.runoob.com/jsref/jsref-setutcmilliseconds.html) | 根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。 | +| [setUTCMinutes()](https://www.runoob.com/jsref/jsref-setutcminutes.html) | 根据世界时设置 Date 对象中的分钟 (0 ~ 59)。 | +| [setUTCMonth()](https://www.runoob.com/jsref/jsref-setutcmonth.html) | 根据世界时设置 Date 对象中的月份 (0 ~ 11)。 | +| [setUTCSeconds()](https://www.runoob.com/jsref/jsref-setutcseconds.html) | setUTCSeconds() 方法用于根据世界时 (UTC) 设置指定时间的秒字段。 | +| setYear() | 已废弃。请使用 setFullYear() 方法代替。 | +| [toDateString()](https://www.runoob.com/jsref/jsref-todatestring.html) | 把 Date 对象的日期部分转换为字符串。 | +| toGMTString() | 已废弃。请使用 toUTCString() 方法代替。 | +| [toISOString()](https://www.runoob.com/jsref/jsref-toisostring.html) | 使用 ISO 标准返回字符串的日期格式。 | +| [toJSON()](https://www.runoob.com/jsref/jsref-tojson.html) | 以 JSON 数据格式返回日期字符串。 | +| [toLocaleDateString()](https://www.runoob.com/jsref/jsref-tolocaledatestring.html) | 根据本地时间格式,把 Date 对象的日期部分转换为字符串。 | +| [toLocaleTimeString()](https://www.runoob.com/jsref/jsref-tolocaletimestring.html) | 根据本地时间格式,把 Date 对象的时间部分转换为字符串。 | +| [toLocaleString()](https://www.runoob.com/jsref/jsref-tolocalestring.html) | 根据本地时间格式,把 Date 对象转换为字符串。 | +| [toString()](https://www.runoob.com/jsref/jsref-tostring-date.html) | 把 Date 对象转换为字符串。 | +| [toTimeString()](https://www.runoob.com/jsref/jsref-totimestring.html) | 把 Date 对象的时间部分转换为字符串。 | +| [toUTCString()](https://www.runoob.com/jsref/jsref-toutcstring.html) | 根据世界时,把 Date 对象转换为字符串。实例:`var today = new Date(); var UTCstring = today.toUTCString();` | +| [UTC()](https://www.runoob.com/jsref/jsref-utc.html) | 根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。 | +| [valueOf()](https://www.runoob.com/jsref/jsref-valueof-date.html) | 返回 Date 对象的原始值。 | + +### 4.3.4 Math + +> 和JAVA中的Math类比较类似 + +| 方法 | 描述 | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| [abs(x)](https://www.runoob.com/jsref/jsref-abs.html) | 返回 x 的绝对值。 | +| [acos(x)](https://www.runoob.com/jsref/jsref-acos.html) | 返回 x 的反余弦值。 | +| [asin(x)](https://www.runoob.com/jsref/jsref-asin.html) | 返回 x 的反正弦值。 | +| [atan(x)](https://www.runoob.com/jsref/jsref-atan.html) | 以介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值。 | +| [atan2(y,x)](https://www.runoob.com/jsref/jsref-atan2.html) | 返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间)。 | +| [ceil(x)](https://www.runoob.com/jsref/jsref-ceil.html) | 对数进行上舍入。 | +| [cos(x)](https://www.runoob.com/jsref/jsref-cos.html) | 返回数的余弦。 | +| [exp(x)](https://www.runoob.com/jsref/jsref-exp.html) | 返回 Ex 的指数。 | +| [floor(x)](https://www.runoob.com/jsref/jsref-floor.html) | 对 x 进行下舍入。 | +| [log(x)](https://www.runoob.com/jsref/jsref-log.html) | 返回数的自然对数(底为e)。 | +| [max(x,y,z,...,n)](https://www.runoob.com/jsref/jsref-max.html) | 返回 x,y,z,...,n 中的最高值。 | +| [min(x,y,z,...,n)](https://www.runoob.com/jsref/jsref-min.html) | 返回 x,y,z,...,n中的最低值。 | +| [pow(x,y)](https://www.runoob.com/jsref/jsref-pow.html) | 返回 x 的 y 次幂。 | +| [random()](https://www.runoob.com/jsref/jsref-random.html) | 返回 0 ~ 1 之间的随机数。 | +| [round(x)](https://www.runoob.com/jsref/jsref-round.html) | 四舍五入。 | +| [sin(x)](https://www.runoob.com/jsref/jsref-sin.html) | 返回数的正弦。 | +| [sqrt(x)](https://www.runoob.com/jsref/jsref-sqrt.html) | 返回数的平方根。 | +| [tan(x)](https://www.runoob.com/jsref/jsref-tan.html) | 返回角的正切。 | +| [tanh(x)](https://www.runoob.com/jsref/jsref-tanh.html) | 返回一个数的双曲正切函数值。 | +| [trunc(x)](https://www.runoob.com/jsref/jsref-trunc.html) | 将数字的小数部分去掉,只保留整数部分。 | + +### 4.3.5 Number + +> Number中准备了一些基础的数据处理函数 + +| 方法 | 描述 | +| :----------------------------------------------------------- | :--------------------------------------------------- | +| [isFinite](https://www.runoob.com/jsref/jsref-isfinite-number.html) | 检测指定参数是否为无穷大。 | +| [isInteger](https://www.runoob.com/jsref/jsref-isinteger-number.html) | 检测指定参数是否为整数。 | +| [isNaN](https://www.runoob.com/jsref/jsref-isnan-number.html) | 检测指定参数是否为 NaN。 | +| [isSafeInteger](https://www.runoob.com/jsref/jsref-issafeInteger-number.html) | 检测指定参数是否为安全整数。 | +| [toExponential(x)](https://www.runoob.com/jsref/jsref-toexponential.html) | 把对象的值转换为指数计数法。 | +| [toFixed(x)](https://www.runoob.com/jsref/jsref-tofixed.html) | 把数字转换为字符串,结果的小数点后有指定位数的数字。 | +| [toLocaleString(locales, options)](https://www.runoob.com/jsref/jsref-tolocalestring-number.html) | 返回数字在特定语言环境下的表示字符串。 | +| [toPrecision(x)](https://www.runoob.com/jsref/jsref-toprecision.html) | 把数字格式化为指定的长度。 | +| [toString()](https://www.runoob.com/jsref/jsref-tostring-number.html) | 把数字转换为字符串,使用指定的基数。 | +| [valueOf()](https://www.runoob.com/jsref/jsref-valueof-number.html) | 返回一个 Number 对象的基本数字值。 | + +### 4.3.6 String + +> 和JAVA中的String类似 + +| 方法 | 描述 | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| [charAt()](https://www.runoob.com/jsref/jsref-charat.html) | 返回在指定位置的字符。 | +| [charCodeAt()](https://www.runoob.com/jsref/jsref-charcodeat.html) | 返回在指定的位置的字符的 Unicode 编码。 | +| [concat()](https://www.runoob.com/jsref/jsref-concat-string.html) | 连接两个或更多字符串,并返回新的字符串。 | +| [endsWith()](https://www.runoob.com/jsref/jsref-endswith.html) | 判断当前字符串是否是以指定的子字符串结尾的(区分大小写)。 | +| [fromCharCode()](https://www.runoob.com/jsref/jsref-fromcharcode.html) | 将 Unicode 编码转为字符。 | +| [indexOf()](https://www.runoob.com/jsref/jsref-indexof.html) | 返回某个指定的字符串值在字符串中首次出现的位置。 | +| [includes()](https://www.runoob.com/jsref/jsref-string-includes.html) | 查找字符串中是否包含指定的子字符串。 | +| [lastIndexOf()](https://www.runoob.com/jsref/jsref-lastindexof.html) | 从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。 | +| [match()](https://www.runoob.com/jsref/jsref-match.html) | 查找找到一个或多个正则表达式的匹配。 | +| [repeat()](https://www.runoob.com/jsref/jsref-repeat.html) | 复制字符串指定次数,并将它们连接在一起返回。 | +| [replace()](https://www.runoob.com/jsref/jsref-replace.html) | 在字符串中查找匹配的子串,并替换与正则表达式匹配的子串。 | +| [replaceAll()](https://www.runoob.com/jsref/jsref-replaceall.html) | 在字符串中查找匹配的子串,并替换与正则表达式匹配的所有子串。 | +| [search()](https://www.runoob.com/jsref/jsref-search.html) | 查找与正则表达式相匹配的值。 | +| [slice()](https://www.runoob.com/jsref/jsref-slice-string.html) | 提取字符串的片断,并在新的字符串中返回被提取的部分。 | +| [split()](https://www.runoob.com/jsref/jsref-split.html) | 把字符串分割为字符串数组。 | +| [startsWith()](https://www.runoob.com/jsref/jsref-startswith.html) | 查看字符串是否以指定的子字符串开头。 | +| [substr()](https://www.runoob.com/jsref/jsref-substr.html) | 从起始索引号提取字符串中指定数目的字符。 | +| [substring()](https://www.runoob.com/jsref/jsref-substring.html) | 提取字符串中两个指定的索引号之间的字符。 | +| [toLowerCase()](https://www.runoob.com/jsref/jsref-tolowercase.html) | 把字符串转换为小写。 | +| [toUpperCase()](https://www.runoob.com/jsref/jsref-touppercase.html) | 把字符串转换为大写。 | +| [trim()](https://www.runoob.com/jsref/jsref-trim.html) | 去除字符串两边的空白。 | +| [toLocaleLowerCase()](https://www.runoob.com/jsref/jsref-tolocalelowercase.html) | 根据本地主机的语言环境把字符串转换为小写。 | +| [toLocaleUpperCase()](https://www.runoob.com/jsref/jsref-tolocaleuppercase.html) | 根据本地主机的语言环境把字符串转换为大写。 | +| [valueOf()](https://www.runoob.com/jsref/jsref-valueof-string.html) | 返回某个字符串对象的原始值。 | +| [toString()](https://www.runoob.com/jsref/jsref-tostring.html) | 返回一个字符串。 | + +# 五 事件的绑定 + +## 5.1 什么是事件 + +> HTML 事件可以是浏览器行为,也可以是用户行为。 当这些一些行为发生时,可以自动触发对应的JS函数的运行,我们称之为事件发生.JS的事件驱动指的就是行为触发代码运行的这种特点 + +## 5.2 常见事件 + +> 鼠标事件 + +| 属性 | 描述 | +| :----------------------------------------------------------- | :------------------------------------- | +| [onclick](https://www.runoob.com/jsref/event-onclick.html) | 当用户点击某个对象时调用的事件句柄。 | +| [oncontextmenu](https://www.runoob.com/jsref/event-oncontextmenu.html) | 在用户点击鼠标右键打开上下文菜单时触发 | +| [ondblclick](https://www.runoob.com/jsref/event-ondblclick.html) | 当用户双击某个对象时调用的事件句柄。 | +| [onmousedown](https://www.runoob.com/jsref/event-onmousedown.html) | 鼠标按钮被按下。 | +| [onmouseenter](https://www.runoob.com/jsref/event-onmouseenter.html) | 当鼠标指针移动到元素上时触发。 | +| [onmouseleave](https://www.runoob.com/jsref/event-onmouseleave.html) | 当鼠标指针移出元素时触发 | +| [onmousemove](https://www.runoob.com/jsref/event-onmousemove.html) | 鼠标被移动。 | +| [onmouseover](https://www.runoob.com/jsref/event-onmouseover.html) | 鼠标移到某元素之上。 | +| [onmouseout](https://www.runoob.com/jsref/event-onmouseout.html) | 鼠标从某元素移开。 | +| [onmouseup](https://www.runoob.com/jsref/event-onmouseup.html) | 鼠标按键被松开。 | + +> 键盘事件 + +| 属性 | 描述 | +| :----------------------------------------------------------- | :------------------------- | +| [onkeydown](https://www.runoob.com/jsref/event-onkeydown.html) | 某个键盘按键被按下。 | +| [onkeypress](https://www.runoob.com/jsref/event-onkeypress.html) | 某个键盘按键被按下并松开。 | +| [onkeyup](https://www.runoob.com/jsref/event-onkeyup.html) | 某个键盘按键被松开。 | + +> 表单事件 + +| 属性 | 描述 | +| :----------------------------------------------------------- | :----------------------------------------------------------- | +| [onblur](https://www.runoob.com/jsref/event-onblur.html) | 元素失去焦点时触发 | +| [onchange](https://www.runoob.com/jsref/event-onchange.html) | 该事件在表单元素的内容改变时触发( , , +
+ 籍贯: + +
+ + +
+ 显示爱好:{{ hbs }} +
+ 显示用户信息:{{ user }} + + + + + +``` + +### 6.5 属性计算 + +> 模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象: + +```html + + + + + +``` + ++ 这里的模板看起来有些复杂。我们必须认真看好一会儿才能明白它的计算依赖于 `author.books`。更重要的是,如果在模板中需要不止一次这样的计算,我们可不想将这样的代码在模板里重复好多遍。 + +> 因此我们推荐使用**计算属性**来描述依赖响应式状态的复杂逻辑。这是重构后的示例: + +```html + + + + + + +``` + ++ 我们在这里定义了一个计算属性 `publishedBooksMessage`。`computed()` 方法期望接收一个 getter 函数,返回值为一个**计算属性 ref**。和其他一般的 ref 类似,你可以通过 `publishedBooksMessage.value` 访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 `.value`。 + ++ Vue 的计算属性会自动追踪响应式依赖。它会检测到 `publishedBooksMessage` 依赖于 `author.books`,所以当 `author.books` 改变时,任何依赖于 `publishedBooksMessage` 的绑定都会同时更新。 + +> 计算属性缓存 vs 方法 + ++ 若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于**计算属性值会基于其响应式依赖被缓存**。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 `author.books` 不改变,无论多少次访问 `publishedBooksMessage` 都会立即返回先前的计算结果! + +### 6.6 数据监听器 + +> 计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。我们可以使用 [watch](https://cn.vuejs.org/api/reactivity-core.html#watch "watch")[ 函数](https://cn.vuejs.org/api/reactivity-core.html#watch " 函数")在每次响应式状态发生变化时触发回调函数: + ++ watch主要用于以下场景: + + 当数据发生变化时需要执行相应的操作 + + 监听数据变化,当满足一定条件时触发相应操作 + + 在异步操作前或操作后需要执行相应的操作 + +> 监控响应式数据(watch): + +```html + + + + + +``` + +> 监控响应式数据(watchEffect): + ++ watchEffect默认监听所有的响应式数据 + +```html + + + + + +``` + +> `watch` vs. `watchEffect` + ++ `watch` 和 `watchEffect` 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式: + + `watch` 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。`watch` 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。 + + `watchEffect`,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。 + +### 6.7. Vue生命周期 + +#### 6.7.1 生命周期简介 + +> 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为`生命周期钩子的函数`,让开发者有机会在特定阶段运行自己的代码! + ++ 周期图解: + + + ++ 常见钩子函数 + + onMounted() 注册一个回调函数,在组件挂载完成后执行。 + + onUpdated() 注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。 + + onUnmounted() 注册一个回调函数,在组件实例被卸载之后调用。 + + onBeforeMount() 注册一个钩子,在组件被挂载之前被调用。 + + onBeforeUpdate() 注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。 + + onBeforeUnmount() 注册一个钩子,在组件实例被卸载之前调用。 + +#### 6.7.2 生命周期案例 + +```html + + + + + +``` + +### 6.8 Vue组件 + +#### 6.8.1 组件基础 + +> 组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。组件就是实现应用中局部功能代码和资源的集合!在实际应用中,组件常常被组织成层层嵌套的树状结构: + + + ++ 这和我们嵌套 HTML 元素的方式类似,Vue 实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。 + +> 传统方式编写应用: + + + +> 组件方式编写应用: + + + ++ 组件化:对js/css/html统一封装,这是VUE中的概念 + ++ 模块化:对js的统一封装,这是ES6中的概念 ++ 组件化中,对js部分代码的处理使用ES6中的模块化 + +#### 6.8.2 组件化入门案例 + +> 案例需求: 创建一个页面,包含头部和菜单以及内容显示区域,每个区域使用独立组建! + +![1686885192862](images/1686885192862.png) + +> 1 准备vue项目 + +```shell +npm create vite +cd vite项目 +npm install +``` + +> 2 安装相关依赖 + +```shell +npm install sass +npm install bootstrap +``` + +> 3 创建子组件 在src/components文件下 vscode需要安装Vetur插件,这样vue文件有快捷提示 + ++ Header.vue + +```html + + + + + +``` + ++ Navigator.vue + +```html + + + + + +``` + ++ Content.vue + +```html + + + + + +``` + ++ App.vue 入口组件App引入组件 + +```html + + + + + +``` + +> 4 启动测试 + +```shell +npm run dev +``` + +#### 6.8.3 组件之间传递数据 + +##### 6.8.3.1 父传子 + +> Vue3 中父组件向子组件传值可以通过 props 进行,具体操作如下: + +1. 首先,在父组件中定义需要传递给子组件的值,接着,在父组件的模板中引入子组件,同时在引入子组件的标签中添加 props 属性并为其设置需要传递的值。 + +2. 在 Vue3 中,父组件通过 props 传递给子组件的值是响应式的。也就是说,如果在父组件中的传递的值发生了改变,子组件中的值也会相应地更新。 + ++ 父组件代码:App.vue + +```html + + + + + +``` ++ 子组件代码:Son.vue + +```html + + + + + +``` + +##### 6.8.3.2 子传父 + ++ 父组件: App.vue + +```html + + + + + + + +``` ++ 子组件:Son.vue + +```html + + + + +``` + + + +##### 6.8.3.3 兄弟传参 + +![](images/image_hZ6yocZGY3.png) + ++ Navigator.vue: 发送数据到App.vue + +```html + + + + + +``` ++ App.vue: 发送数据到Content.vue + +```html + + + + + +``` ++ Content.vue + +```html + + + + + +``` + +## 七、Vue3路由机制router + +### 7.1 路由简介 + +> 1 什么是路由? + +- 定义:路由就是根据不同的 URL 地址展示不同的内容或页面。 +- 通俗理解:路由就像是一个地图,我们要去不同的地方,需要通过不同的路线进行导航。 + +> 2 路由的作用 + +- 单页应用程序(SPA)中,路由可以实现不同视图之间的无刷新切换,提升用户体验; +- 路由还可以实现页面的认证和权限控制,保护用户的隐私和安全; +- 路由还可以利用浏览器的前进与后退,帮助用户更好地回到之前访问过的页面。 + +### 7.2 路由入门案例 + +> 1 案例需求分析 + + + +​ + +> 2 创建项目和导入路由依赖 + + +```shell +npm create vite //创建项目cd 项目文件夹 //进入项目文件夹 +npm install //安装项目需求依赖 +npm install vue-router@4 --save //安装全局的vue-router 4版本 +``` + +> 3 准备页面和组件 + ++ components/Home.vue + +``` html + + + + + + +``` + ++ components/List.vue + +``` html + + + + + +``` + ++ components/Add.vue + +``` html + + + + + +``` + ++ components/Update.vue + +``` html + + + + + +``` + ++ App.vue + +``` html + + + + + + +``` + +> 4 准备路由配置 + ++ src/routers/router.js + +```javascript +// 导入路由创建的相关方法 +import {createRouter,createWebHashHistory} from 'vue-router' + +// 导入vue组件 +import Home from '../components/Home.vue' +import List from '../components/List.vue' +import Add from '../components/Add.vue' +import Update from '../components/Update.vue' + +// 创建路由对象,声明路由规则 +const router = createRouter({ + //createWebHashHistory() 是 Vue.js 基于 hash 模式创建路由的工厂函数。在使用这种模式下,路由信息保存在 URL 的 hash 中, + //使用 createWebHashHistory() 方法,可以创建一个路由历史记录对象,用于管理应用程序的路由。在 Vue.js 应用中, + //通常使用该方法来创建路由的历史记录对象。 + //就是路由中缓存历史记录的对象,vue-router提供 + history: createWebHashHistory(), + routes:[ + { + path:'/', + /* + component指定组件在默认的路由视图位置展示 + components:Home + components指定组件在name为某个值的路由视图位置展示 + components:{ + default:Home,// 默认路由视图位置 + homeView:Home// name为homeView的路由视图位置 + } + */ + components:{ + default:Home, + homeView:Home + } + }, + { + path:'/list', + components:{ + listView : List + } + }, + { + path:'/add', + components:{ + addView:Add + } + }, + { + path:'/update', + components:{ + updateView:Update + } + }, + ] + +}) + +// 对外暴露路由对象 +export default router; +``` + +> 5 main.js引入router配置 + ++ 修改文件:main.js (入口文件) + +```javascript +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' +//导入router模块 +import router from './routers/router.js' +let app = createApp(App) +//绑定路由对象 +app.use(router) +//挂在试图 +app.mount("#app") +``` + +> 6 启动测试 + +``` shell +npm run dev +``` + +### 7.3 路由重定向 + +> 重定向的作用:将一个路由重定向到另一个路由上 + ++ 修改案例:访问/list和/showAll都定向到List.vue ++ router.js + +``` javascript +// 导入路由创建的相关方法 +import {createRouter,createWebHashHistory} from 'vue-router' + +// 导入vue组件 +import Home from '../components/Home.vue' +import List from '../components/List.vue' +import Add from '../components/Add.vue' +import Update from '../components/Update.vue' + +// 创建路由对象,声明路由规则 +const router = createRouter({ + history: createWebHashHistory(), + routes:[ + { + path:'/', + components:{ + default:Home, + homeView:Home + } + }, + { + path:'/list', + components:{ + listView : List + } + }, + { + path:'/showAll', + // 重定向 + redirect :'/list' + }, + { + path:'/add', + components:{ + addView:Add + } + }, + { + path:'/update', + components:{ + updateView:Update + } + }, + ] + +}) + +// 对外暴露路由对象 +export default router; +``` + ++ App.vue + +```html + + + + + +``` + +### 7.4 编程式路由(useRouter) + +> 普通路由 + ++ `list页 `这种路由,to中的内容目前是固定的,点击后只能切换/list对象组件(声明式路由) + +> 编程式路由 + ++ 通过useRouter,动态决定向那个组件切换的路由 ++ 在 Vue 3 和 Vue Router 4 中,你可以使用 `useRouter` 来实现动态路由(编程式路由) ++ 这里的 `useRouter` 方法返回的是一个 router 对象,你可以用它来做如导航到新页面、返回上一页面等操作。 + +> 案例需求: 通过普通按钮配合事件绑定实现路由页面跳转,不直接使用router-link标签 + ++ App.vue + +``` html + + + + + +``` + +### 7.5 路由传参(useRoute) + +> 路径参数 + ++ 在路径中使用一个动态字段来实现,我们称之为 **路径参数** + + 例如: 查看数据详情 `/showDetail/1` ,`1`就是要查看详情的id,可以动态添值! + +> 键值对参数 + ++ 类似与get请求通过url传参,数据是键值对形式的 + + + 例如: 查看数据详情`/showDetail?hid=1`,`hid=1`就是要传递的键值对参数 + + + 在 Vue 3 和 Vue Router 4 中,你可以使用 `useRoute` 这个函数从 Vue 的组合式 API 中获取路由对象。 + + `useRoute` 方法返回的是当前的 route 对象,你可以用它来获取关于当前路由的信息,如当前的路径、查询参数等。 + +> 案例需求 : 切换到ShowDetail.vue组件时,向该组件通过路由传递参数 + ++ 修改App.vue文件 + +``` html + + + + + + +``` + ++ 修改router.js增加路径参数占位符 + +``` javascript +// 导入路由创建的相关方法 +import {createRouter,createWebHashHistory} from 'vue-router' + +// 导入vue组件 + +import ShowDetail from '../components/ShowDetail.vue' +import ShowDetail2 from '../components/ShowDetail2.vue' + +// 创建路由对象,声明路由规则 +const router = createRouter({ + history: createWebHashHistory(), + routes:[ + + { + /* 此处:id :language作为路径的占位符 */ + path:'/showDetail/:id/:language', + /* 动态路由传参时,根据该名字找到该路由 */ + name:'showDetail', + components:{ + showDetailView:ShowDetail + } + }, + { + path:'/showDetail2', + components:{ + showDetailView2:ShowDetail2 + } + }, + ] + +}) + +// 对外暴露路由对象 +export default router; +``` + ++ ShowDetail.vue 通过useRoute获取路径参数 + +``` html + + + + + + +``` + +- ShowDetail2.vue通过useRoute获取键值对参数 +```html + + + + + + +``` +### 7.6 路由守卫 + +> 在 Vue 3 中,路由守卫是用于在路由切换期间进行一些特定任务的回调函数。路由守卫可以用于许多任务,例如验证用户是否已登录、在路由切换前提供确认提示、请求数据等。Vue 3 为路由守卫提供了全面的支持,并提供了以下几种类型的路由守卫: + +1. **全局前置守卫**:在路由切换前被调用,可以用于验证用户是否已登录、中断导航、请求数据等。 +2. **全局后置守卫**:在路由切换之后被调用,可以用于处理数据、操作 DOM 、记录日志等。 +3. **守卫代码的位置**: 在router.js中 + +```javascript +//全局前置路由守卫 +router.beforeEach( (to,from,next) => { + //to 是目标地包装对象 .path属性可以获取地址 + //from 是来源地包装对象 .path属性可以获取地址 + //next是方法,不调用默认拦截! next() 放行,直接到达目标组件 + //next('/地址')可以转发到其他地址,到达目标组件前会再次经过前置路由守卫 + console.log(to.path,from.path,next) + + //需要判断,注意避免无限重定向 + if(to.path == '/index'){ + next() + }else{ + next('/index') + } + +} ) + +//全局后置路由守卫 +router.afterEach((to, from) => { + console.log(`Navigate from ${from.path} to ${to.path}`); +}); + +``` + + + +> 登录案例,登录以后才可以进入home,否则必须进入login + ++ 定义Login.vue + +```html + + + + + + +``` + ++ 定义Home.vue + +```html + + + + + + +``` + ++ App.vue + +```html + + + + + + +``` + ++ 定义routers.js + +``` javascript +// 导入路由创建的相关方法 +import {createRouter,createWebHashHistory} from 'vue-router' + +// 导入vue组件 + +import Home from '../components/Home.vue' +import Login from '../components/login.vue' +// 创建路由对象,声明路由规则 +const router = createRouter({ + history: createWebHashHistory(), + routes:[ + { + path:'/home', + component:Home + }, + { + path:'/', + redirect:"/home" + }, + { + path:'/login', + component:Login + }, + ] + +}) + +// 设置路由的全局前置守卫 +router.beforeEach((to,from,next)=>{ + /* + to 要去那 + from 从哪里来 + next 放行路由时需要调用的方法,不调用则不放行 + */ + console.log(`从哪里来:${from.path},到哪里去:${to.path}`) + + if(to.path == '/login'){ + //放行路由 注意放行不要形成循环 + next() + }else{ + //let username =window.sessionStorage.getItem('username'); + let username =window.localStorage.getItem('username'); + if(null != username){ + next() + }else{ + next('/login') + } + + } +}) +// 设置路由的全局后置守卫 +router.afterEach((to,from)=>{ + console.log(`从哪里来:${from.path},到哪里去:${to.path}`) +}) + +// 对外暴露路由对象 +export default router; +``` + ++ 启动测试 + +```shell +npm run dev +``` + +## 八、 案例开发-日程管理-第五期 + +### 8.1 重构前端工程 + +> 业务目标展示 + ++ 登录页 + +![1690533751478](images/1690533751478.png) + ++ 注册页 + +![1690533770048](images/1690533770048.png) + ++ 日程管理页 + +![1690533809917](images/1690533809917.png) + +> 创建项目,安装依赖 + +``` shell +npm create vite +cd 项目目录 +npm install +npm install vue-router +``` + ++ 项目结构如下 + +![1690516506417](images/1690516506417.png) + +> 开发视图 + ++ Header.vue视图 + +``` html + + + + + + +``` + + + ++ Login.vue视图 + +``` html + + + + + + +``` + ++ Regist.vue视图 + +``` html + + + + + + +``` + ++ ShowSchedule.vue视图 + +``` html + + + + + + +``` + ++ App.vue视图 + +``` html + + + + + + +``` + + + ++ 配置路由 + +``` javascript +import {createRouter,createWebHashHistory} from 'vue-router' + + +import Login from '../components/Login.vue' +import Regist from '../components/Regist.vue' +import ShowScedule from '../components/ShowSchedule.vue' + +let router = createRouter({ + history:createWebHashHistory(), + routes:[ + { + path:"/", + component:Login + }, + { + path:"/login", + component:Login + }, + { + path:"/showSchedule", + component:ShowScedule + }, + { + path:"/regist", + component:Regist + } + + + ] +}) + +export default router +``` + + + ++ 配置main.js + +``` javascript +import { createApp } from 'vue' + +import App from './App.vue' + +// 导入路由 +import router from './router/router.js' + +let app =createApp(App) + +// 全局使用路由 +app.use(router) + +app.mount('#app') + +``` + + + + + +## 九、Vue3数据交互axios + +### 9.0 预讲知识-promise + +#### 9.0.1 普通函数和回调函数 + +> 普通函数: 正常调用的函数,一般函数执行完毕后才会继续执行下一行代码 + +``` html + +``` + +> 回调函数: 一些特殊的函数,表示未来才会执行的一些功能,后续代码不会等待该函数执行完毕就开始执行了 + +```html + +``` + + + +#### 9.0.2 Promise 简介 + +> 前端中的异步编程技术,类似Java中的多线程+线程结果回调! + ++ Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了`Promise`对象。 + ++ 所谓`Promise`,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。 + +> `Promise`对象有以下两个特点。 + + (1)Promise对象代表一个异步操作,有三种状态:`Pending`(进行中)、`Resolved`(已完成,又称 Fulfilled)和`Rejected`(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是`Promise`这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。 + + (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从`Pending`变为`Resolved`和从`Pending`变为`Rejected`。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。 + +#### 9.0.3 Promise 基本用法 + +> ES6规定,Promise对象是一个构造函数,用来生成Promise实例。 + +```html + +``` + +#### 9.0.4 Promise catch() + +> `Promise.prototype.catch`方法是`.then(null, rejection)`的别名,用于指定发生错误时的回调函数。 + +```html + +``` + +#### 9.0.5 async和await的使用 + +> async和await是ES6中用于处理异步操作的新特性。通常,异步操作会涉及到Promise对象,而async/await则是在Promise基础上提供了更加直观和易于使用的语法。 + +> async 用于标识函数的 + +1. async标识函数后,async函数的返回值会变成一个promise对象 + +2. 如果函数内部返回的数据是一个非promise对象,async函数的结果会返回一个成功状态 promise对象 + +3. 如果函数内部返回的是一个promise对象,则async函数返回的状态与结果由该对象决定 + +4. 如果函数内部抛出的是一个异常,则async函数返回的是一个失败的promise对象 + +``` html + +``` + +> await + +1. await右侧的表达式一般为一个promise对象,但是也可以是一个其他值 +2. 如果表达式是promise对象,await返回的是promise成功的值 +3. await会等右边的promise对象执行结束,然后再获取结果,后续代码也会等待await的执行 +4. 如果表达式是其他值,则直接返回该值 +5. await必须在async函数中,但是async函数中可以没有await +6. 如果await右边的promise失败了,就会抛出异常,需要通过 try ... catch捕获处理 + +``` html + +``` + + + +### 9.1 Axios介绍 + +> ajax + ++ AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 + ++ AJAX 不是新的编程语言,而是一种使用现有标准的新方法。 + ++ AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。 + ++ AJAX 不需要任何浏览器插件,但需要用户允许 JavaScript 在浏览器上执行。 + ++ XMLHttpRequest 只是实现 Ajax 的一种方式。 + +**ajax工作原理:** + +![](images/image_bjXPJoLb6a.png) + +> 原生**javascript方式进行ajax(了解):** + +```html + +``` + +> 什么是axios 官网介绍:https://axios-http.com/zh/docs/intro + ++ Axios 是一个基于 [*promise*](https://javascript.info/promise-basics "promise") 网络请求库,作用于[node.js](https://nodejs.org/ "node.js") 和浏览器中。 它是 [*isomorphic*](https://www.lullabot.com/articles/what-is-an-isomorphic-application "isomorphic") 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js `http` 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。它有如下特性 + + 从浏览器创建 [XMLHttpRequests](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest "XMLHttpRequests") + + 从 node.js 创建 [http](http://nodejs.org/api/http.html "http") 请求 + + 支持 [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise "Promise") API + + 拦截请求和响应 + + 转换请求和响应数据 + + 取消请求 + + 自动转换JSON数据 + + 客户端支持防御[XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery "XSRF") + +### 9.2 Axios 入门案例 + +> 1 案例需求:请求后台获取随机土味情话 + ++ 请求的url + +``` http +https://api.uomg.com/api/rand.qinghua?format=json 或者使用 http://forum.atguigu.cn/api/rand.qinghua?format=json +``` + ++ 请求的方式 + +``` http +GET/POST +``` + ++ 数据返回的格式 + +```json +{"code":1,"content":"我努力不是为了你而是因为你。"} +``` + +> 2 准备项目 + +```javascript +npm create vite +npm install +/*npm install vue-router@4 --save +npm install pinia */ +``` + +> 3 安装axios + +```shell +npm install axios +``` + +> 4 设计页面(App.Vue) + +```html + + + + + + +``` + +> 5 启动测试 + +```shell +npm run dev +``` + +> 异步响应的数据结构 + ++ 响应的数据是经过包装返回的!一个请求的响应包含以下信息。 + +```json +{ + // `data` 由服务器提供的响应 + data: {}, + // `status` 来自服务器响应的 HTTP 状态码 + status: 200, + // `statusText` 来自服务器响应的 HTTP 状态信息 + statusText: 'OK', + // `headers` 是服务器响应头 + // 所有的 header 名称都是小写,而且可以使用方括号语法访问 + // 例如: `response.headers['content-type']` + headers: {}, + // `config` 是 `axios` 请求的配置信息 + config: {}, + // `request` 是生成此响应的请求 + // 在node.js中它是最后一个ClientRequest实例 (in redirects), + // 在浏览器中则是 XMLHttpRequest 实例 + request: {} +} +``` ++ then取值 + +```javascript +then(function (response) { + console.log(response.data); + console.log(response.status); + console.log(response.statusText); + console.log(response.headers); + console.log(response.config); +}); +``` + + +> 6 通过async和await处理异步请求 + +```html + + + + + + +``` + +> axios在发送异步请求时的可选配置: + +```json +{ + // `url` 是用于请求的服务器 URL + url: '/user', + // `method` 是创建请求时使用的方法 + method: 'get', // 默认值 + // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。 + // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL + baseURL: 'https://some-domain.com/api/', + // `transformRequest` 允许在向服务器发送前,修改请求数据 + // 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法 + // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream + // 你可以修改请求头。 + transformRequest: [function (data, headers) { + // 对发送的 data 进行任意转换处理 + return data; + }], + // `transformResponse` 在传递给 then/catch 前,允许修改响应数据 + transformResponse: [function (data) { + // 对接收的 data 进行任意转换处理 + return data; + }], + // 自定义请求头 + headers: {'X-Requested-With': 'XMLHttpRequest'}, + // `params` 是与请求一起发送的 URL 参数 + // 必须是一个简单对象或 URLSearchParams 对象 + params: { + ID: 12345 + }, + // `paramsSerializer`是可选方法,主要用于序列化`params` + // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) + paramsSerializer: function (params) { + return Qs.stringify(params, {arrayFormat: 'brackets'}) + }, + // `data` 是作为请求体被发送的数据 + // 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法 + // 在没有设置 `transformRequest` 时,则必须是以下类型之一: + // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams + // - 浏览器专属: FormData, File, Blob + // - Node 专属: Stream, Buffer + data: { + firstName: 'Fred' + }, + // 发送请求体数据的可选语法 + // 请求方式 post + // 只有 value 会被发送,key 则不会 + data: 'Country=Brasil&City=Belo Horizonte', + // `timeout` 指定请求超时的毫秒数。 + // 如果请求时间超过 `timeout` 的值,则请求会被中断 + timeout: 1000, // 默认值是 `0` (永不超时) + // `withCredentials` 表示跨域请求时是否需要使用凭证 + withCredentials: false, // default + // `adapter` 允许自定义处理请求,这使测试更加容易。 + // 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。 + adapter: function (config) { + /* ... */ + }, + // `auth` HTTP Basic Auth + auth: { + username: 'janedoe', + password: 's00pers3cret' + }, + // `responseType` 表示浏览器将要响应的数据类型 + // 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream' + // 浏览器专属:'blob' + responseType: 'json', // 默认值 + // `responseEncoding` 表示用于解码响应的编码 (Node.js 专属) + // 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求 + // Note: Ignored for `responseType` of 'stream' or client-side requests + responseEncoding: 'utf8', // 默认值 + // `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称 + xsrfCookieName: 'XSRF-TOKEN', // 默认值 + // `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称 + xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值 + // `onUploadProgress` 允许为上传处理进度事件 + // 浏览器专属 + onUploadProgress: function (progressEvent) { + // 处理原生进度事件 + }, + // `onDownloadProgress` 允许为下载处理进度事件 + // 浏览器专属 + onDownloadProgress: function (progressEvent) { + // 处理原生进度事件 + }, + // `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数 + maxContentLength: 2000, + // `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数 + maxBodyLength: 2000, + // `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。 + // 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`), + // 则promise 将会 resolved,否则是 rejected。 + validateStatus: function (status) { + return status >= 200 && status < 300; // 默认值 + }, + // `maxRedirects` 定义了在node.js中要遵循的最大重定向数。 + // 如果设置为0,则不会进行重定向 + maxRedirects: 5, // 默认值 + // `socketPath` 定义了在node.js中使用的UNIX套接字。 + // e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。 + // 只能指定 `socketPath` 或 `proxy` 。 + // 若都指定,这使用 `socketPath` 。 + socketPath: null, // default + // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http + // and https requests, respectively, in node.js. This allows options to be added like + // `keepAlive` that are not enabled by default. + httpAgent: new http.Agent({ keepAlive: true }), + httpsAgent: new https.Agent({ keepAlive: true }), + // `proxy` 定义了代理服务器的主机名,端口和协议。 + // 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。 + // 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。 + // `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。 + // 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。 + // 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https` + proxy: { + protocol: 'https', + host: '127.0.0.1', + port: 9000, + auth: { + username: 'mikeymike', + password: 'rapunz3l' + } + }, + // see https://axios-http.com/zh/docs/cancellation + cancelToken: new CancelToken(function (cancel) { + }), + // `decompress` indicates whether or not the response body should be decompressed + // automatically. If set to `true` will also remove the 'content-encoding' header + // from the responses objects of all decompressed responses + // - Node only (XHR cannot turn off decompression) + decompress: true // 默认值 +} +``` + +### 9.3 Axios get和post方法 + +> 配置添加语法 + +``` javascript +axios.get(url[, config]) + +axios.get(url,{ + 上面指定配置key:配置值, + 上面指定配置key:配置值 +}) + +axios.post(url[, data[, config]]) + +axios.post(url,{key:value //此位置数据,没有空对象即可{}},{ + 上面指定配置key:配置值, + 上面指定配置key:配置值 +}) +``` + + + +> 测试get参数 + +``` html + + + + + + +``` + +> 测试post参数 + +```html + + + + + + +``` + +### 9.4 Axios 拦截器 + +> 如果想在axios发送请求之前,或者是数据响应回来在执行then方法之前做一些额外的工作,可以通过拦截器完成 + +```javascript +// 添加请求拦截器 请求发送之前 +axios.interceptors.request.use( + function (config) { + // 在发送请求之前做些什么 + return config; + }, + function (error) { + // 对请求错误做些什么 + return Promise.reject(error); + } +); + +// 添加响应拦截器 数据响应回来 +axios.interceptors.response.use( + function (response) { + // 2xx 范围内的状态码都会触发该函数。 + // 对响应数据做点什么 + return response; + }, + function (error) { + // 超出 2xx 范围的状态码都会触发该函数。 + // 对响应错误做点什么 + return Promise.reject(error); + } +); +``` + ++ 定义src/axios.js提取拦截器和配置语法 + +```javascript +import axios from 'axios' + + +// 创建instance实例 +const instance = axios.create({ + baseURL:'https://api.uomg.com', + timeout:10000 +}) + +// 添加请求拦截 +instance.interceptors.request.use( + // 设置请求头配置信息 + config=>{ + //处理指定的请求头 + console.log("before request") + config.headers.Accept = 'application/json, text/plain, text/html,*/*' + return config + }, + // 设置请求错误处理函数 + error=>{ + console.log("request error") + return Promise.reject(error) + } +) +// 添加响应拦截器 +instance.interceptors.response.use( + // 设置响应正确时的处理函数 + response=>{ + console.log("after success response") + console.log(response) + return response + }, + // 设置响应异常时的处理函数 + error=>{ + console.log("after fail response") + console.log(error) + return Promise.reject(error) + } +) +// 默认导出 +export default instance +``` + ++ App.vue + +```html + + + + + +``` + + + +## 十、案例开发-日程管理-第六期 + +### 10.1 前端代码处理 + +#### 10.1.1 创建src/utils/request.js文件 + +``` javascript +import axios from 'axios' + +// 创建instance实例 +const instance = axios.create({ + baseURL:'http://localhost:8080/' + +}) + +// 添加请求拦截 +instance.interceptors.request.use( + // 设置请求头配置信息 + config=>{ + //处理指定的请求头 + + return config + }, + // 设置请求错误处理函数 + error=>{ + + return Promise.reject(error) + } +) +// 添加响应拦截器 +instance.interceptors.response.use( + // 设置响应正确时的处理函数 + response=>{ + + return response + }, + // 设置响应异常时的处理函数 + error=>{ + return Promise.reject(error) + } +) +// 默认导出 +export default instance +``` + +#### 10.1.2 注册页面完成注册 + +``` html + + + + +``` + + + +#### 10.1.3 登录页面完成登录 + +``` html + + + + + + + +``` + + + +### 10.2 后端代码处理 + + + +#### 10.2.1 添加跨域处理器 + +##### 10.2.1.1 什么是跨域 + +> 同源策略(Sameoriginpolicy)是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。**`同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号`** + +##### 10.2.1.2为什么会产生跨域 + +> 前后端分离模式下,客户端请求前端服务器获取视图资源,然后客户端自行向后端服务器获取数据资源,前端服务器的 协议,IP和端口和后端服务器很可能是不一样的,这样就产生了跨域 + +![1683364198087](images/1683364198087-1690533535579.png) + +##### 10.2.1.3 如何解决跨域 + +> 前端项目代理模式处理 + +![1683365066926](images/1683365066926-1690533535580.png) + + + +> 后端跨域过滤器方式处理 + +![1683364436315](images/1683364436315-1690533535580.png) + ++ CrosFilter过滤器 + +``` java +package com.atguigu.schedule.filter; + +import com.atguigu.schedule.common.Result; +import com.atguigu.schedule.util.WebUtil; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +@WebFilter("/*") +public class CrosFilter implements Filter { + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + + HttpServletRequest request = (HttpServletRequest) servletRequest; + System.out.println(request.getMethod()); + HttpServletResponse response = (HttpServletResponse) servletResponse; + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT,OPTIONS, DELETE, HEAD"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With"); + // 如果是跨域预检请求,则直接在此响应200业务码 + if(request.getMethod().equalsIgnoreCase("OPTIONS")){ + WebUtil.writeJson(response, Result.ok(null)); + }else{ + // 非预检请求,放行即可 + filterChain.doFilter(servletRequest, servletResponse); + } + } +} + +``` + ++ 未来我们使用框架,直接用一个@CrossOrigin 就可以解决跨域问题了 + +#### 10.2.2 重构UserController + +``` java +package com.atguigu.schedule.controller; + +import com.atguigu.schedule.common.Result; +import com.atguigu.schedule.common.ResultCodeEnum; +import com.atguigu.schedule.pojo.SysUser; +import com.atguigu.schedule.service.SysUserService; +import com.atguigu.schedule.service.impl.SysUserServiceImpl; +import com.atguigu.schedule.util.MD5Util; +import com.atguigu.schedule.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +@WebServlet("/user/*") +public class UserController extends BaseController{ + private SysUserService userService =new SysUserServiceImpl(); + + + /** + * 注册时校验用户名是否被占用的业务接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void checkUsernameUsed(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String username = req.getParameter("username"); + SysUser registUser = userService.findByUsername(username); + + //封装结果对象 + Result result=null; + if(null ==registUser){ + // 未占用,创建一个code为200的对象 + result= Result.ok(null); + }else{ + // 占用, 创建一个结果为505的对象 + result= Result.build(null, ResultCodeEnum.USERNAME_USED); + + } + // 将result对象转换成JSON并响应给客户端 + WebUtil.writeJson(resp,result); + + } + + /** + * 用户注册的业务接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 接收要注册的用户信息 + SysUser registUser = WebUtil.readJson(req, SysUser.class); + // 调用服务层方法,将用户注册进入数据库 + int rows =userService.regist(registUser); + Result result =null; + if(rows>0){ + result=Result.ok(null); + }else{ + result =Result.build(null,ResultCodeEnum.USERNAME_USED); + } + WebUtil.writeJson(resp,result); + } + + /** + * 用户登录的业务接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + + // 接收用户请求参数 + // 获取要登录的用户名密码 + SysUser inputUser = WebUtil.readJson(req, SysUser.class); + // 调用服务层方法,根据用户名查询数据库中是否有一个用户 + SysUser loginUser =userService.findByUsername(inputUser.getUsername()); + + Result result = null; + + if(null == loginUser){ + // 没有根据用户名找到用户,说明用户名有误 + result=Result.build(null,ResultCodeEnum.USERNAME_ERROR); + }else if(! loginUser.getUserPwd().equals(MD5Util.encrypt(inputUser.getUserPwd()))){ + // 用户密码有误, + result=Result.build(null,ResultCodeEnum.PASSWORD_ERROR); + }else{ + // 登录成功 + result=Result.ok(null); + } + + WebUtil.writeJson(resp,result); + + } +} + +``` + + + + + +#### 10.2.3 删除登录校验过滤器 + ++ 这里不使用cookie和session方式记录用户状态,未来使用token,所以登录过滤器删除即可 + +## 十一、Vue3状态管理Pinia + +### 11.1 Pinia介绍 + +> 如何实现多个组件之间的数据传递? + ++ 方式1 组件传参 + ++ 方式2 路由传参 + ++ 方式3 通过pinia状态管理定义共享数据 + +> 当我们有`多个组件共享一个共同的状态(数据源)`时,多个视图可能都依赖于同一份状态。来自不同视图的交互也可能需要更改同一份状态。虽然我们的手动状态管理解决方案(props,组件间通信,模块化)在简单的场景中已经足够了,但是在大规模的生产应用中还有很多其他事项需要考虑: + +- 更强的团队协作约定 +- 与 Vue DevTools 集成,包括时间轴、组件内部审查和时间旅行调试 +- 模块热更新 (HMR) +- 服务端渲染支持 + +> [Pinia](https://pinia.vuejs.org/zh/ "Pinia") 就是一个实现了上述需求的状态管理库,由 Vue 核心团队维护,对 Vue 2 和 Vue 3 都可用。https://pinia.vuejs.org/zh/introduction.html + +### 11.2 Pinia基本用法 + +> 1 准备vite项目 + +```javascript +npm create vite +npm install +npm install vue-router@4 --save +``` + +> 2 安装pinia + +```javascript +npm install pinia +``` + +> 3 定义pinia store对象 src/store/store.js \[推荐这么命名不是强制] + +```javascript +import {defineStore } from 'pinia' + +//定义数据并且对外暴露 +// store就是定义共享状态的包装对象 +// 内部包含四个属性: id 唯一标识 state 完整类型推理,推荐使用箭头函数 存放的数据 getters 类似属性计算,存储放对数据 +// 操作的方法 actions 存储数据的复杂业务逻辑方法 +// 理解: store类似Java中的实体类, id就是类名, state 就是装数据值的属性 getters就是get方法,actions就是对数据操作的其他方法 +export const definedPerson = defineStore( + { + id: 'personPinia', //必须唯一 + state:()=>{ // state中用于定义数据 + return { + username:'张三', + age:0, + hobbies:['唱歌','跳舞'] + } + }, + getters:{// 用于定义一些通过数据计算而得到结果的一些方法 一般在此处不做对数据的修改操作 + // getters中的方法可以当做属性值方式使用 + getHobbiesCount(){ + return this.hobbies.length + }, + getAge(){ + return this.age + } + }, + actions:{ // 用于定义一些对数据修改的方法 + doubleAge(){ + this.age=this.age*2 + } + } + } +) +``` + +> 4 在main.js配置pinia组件到vue中 + +```javascript +import { createApp } from 'vue' +import App from './App.vue' +import router from './routers/router.js' +// 导pinia +import { createPinia } from 'pinia' +// 创建pinia对象 +let pinia= createPinia() + +let app =createApp(App) +app.use(router) +// app中使用pinia功能 +app.use(pinia) +app.mount('#app') +``` + +> 5 Operate.vue 中操作Pinia数据 + +```html + + + + +``` + +> 6 List.vue中展示Pinia数据 + +``` html + + + + + + +``` + +> 7 定义组件路由router.js + +``` javascript +// 导入路由创建的相关方法 +import {createRouter,createWebHashHistory} from 'vue-router' + +// 导入vue组件 +import List from '../components/List.vue' +import Operate from '../components/Operate.vue' +// 创建路由对象,声明路由规则 +const router = createRouter({ + history: createWebHashHistory(), + routes:[ + { + path:'/opearte', + component:Operate + }, + + { + path:'/list', + component:List + }, + ] + +}) + +// 对外暴露路由对象 +export default router; +``` + +> 8 App.vue中通过路由切换组件 + +``` html + + + + + +``` + +> 9 启动测试 + +```javascript +npm run dev +``` + +### 11.3 Pinia其他细节 + +> State (状态) 在大多数情况下,state 都是你的 store 的核心。人们通常会先定义能代表他们 APP 的 state。在 Pinia 中,state 被定义为一个返回初始状态的函数。 + ++ store.js + +```javascript +import {defineStore} from 'pinia' + +export const definedPerson = defineStore('personPinia', + { + state:()=>{ + return { + username:'', + age:0, + hobbies:['唱歌','跳舞'] + } + }, + getters:{ + getHobbiesCount(){ + return this.hobbies.length + }, + getAge(){ + return this.age + } + }, + actions:{ + doubleAge(){ + this.age=this.age*2 + } + } + } +) +``` + ++ Operate.vue + +``` html + + + + + +``` + +> 2 Getter 完全等同于 store 的 state 的[计算值](https://cn.vuejs.org/guide/essentials/computed.html "计算值")。可以通过 `defineStore()` 中的 `getters` 属性来定义它们。**推荐**使用箭头函数,并且它将接收 `state` 作为第一个参数: + +```javascript +export const useStore = defineStore('main', { + state: () => ({ + count: 0, + }), + getters: { + doubleCount: (state) => state.count * 2, + }, +}) +``` + +> 3 Action 相当于组件中的 [method](https://v3.vuejs.org/guide/data-methods.html#methods "method")。它们可以通过 `defineStore()` 中的 `actions` 属性来定义,**并且它们也是定义业务逻辑的完美选择。**类似 [getter](https://pinia.vuejs.org/zh/core-concepts/getters.html "getter"),action 也可通过 `this` 访问**整个 store 实例**,并支持**完整的类型标注(以及自动补全)**。不同的是,`action` 可以是异步的,你可以在它们里面 `await` 调用任何 API,以及其他 action! + +```javascript +export const useCounterStore = defineStore('main', { + state: () => ({ + count: 0, + }), + actions: { + increment() { + this.count++ + }, + randomizeCounter() { + this.count = Math.round(100 * Math.random()) + }, + }, +}) +``` + +## 十二、案例开发-日程管理-第七期 + +### 12.1 前端使用pinia存储数据 + ++ 安装pinia依赖 + +``` shell +npm install pinia +``` + ++ src下创建pinia.js文件 + +``` javascript +// 导入pinia组件 +import {createPinia} from 'pinia' +// 创建pinia对象 +let pinia = createPinia() +// 导出默认的pinia +export default pinia +``` + ++ main.js中使用pinia + +``` js +import { createApp } from 'vue' +import App from './App.vue' +// 导入路由 +import router from './router/router.js' +// 导入pinia对象 +import pinia from './pinia.js' +let app =createApp(App) +// 全局使用路由 +app.use(router) +// 全局使用pinia +app.use(pinia) +app.mount('#app') +``` + ++ src/store/userStore.js 用于存储用户信息 + +``` javascript +import {defineStore} from 'pinia' + +export const defineUser = defineStore('loginUser',{ + state:()=>{ + return { + uid:0, + username:'' + } + }, + getters :{ + + } + +}) +``` + ++ src/store/scheduleStore.js 用于存储用户的日程信息 + +``` javaScript +import {defineStore} from 'pinia' + +export const defineSchedule = defineStore('scheduleList',{ + state:()=>{ + return { + itemList:[ + /*{ + sid:1, + uid:1, + title:'学java', + completed:1 + }, + { + sid:2, + uid:1, + title:'学前端', + completed:0 + }*/ + ] + } + }, + getters :{ + + }, + actions:{ + + } + +}) +``` + ++ Header.vue中,通过pinia的数据来判断展示何种提示 视图 + +``` html + + + + + + + +``` + ++ Login.vue中,登录成功后,接收后端响应回来的用户id和用户名,存储于userStore中 + +``` html + + + + + + + +``` + ++ 服务端登录处理方法,登录成功,返回登录用户的信息 + +``` java + /** + * 用户登录的业务接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + + // 接收用户请求参数 + // 获取要登录的用户名密码 + SysUser inputUser = WebUtil.readJson(req, SysUser.class); + // 调用服务层方法,根据用户名查询数据库中是否有一个用户 + SysUser loginUser =userService.findByUsername(inputUser.getUsername()); + + Result result = null; + + if(null == loginUser){ + // 没有根据用户名找到用户,说明用户名有误 + result=Result.build(null,ResultCodeEnum.USERNAME_ERROR); + }else if(! loginUser.getUserPwd().equals(MD5Util.encrypt(inputUser.getUserPwd()))){ + // 用户密码有误, + result=Result.build(null,ResultCodeEnum.PASSWORD_ERROR); + }else{ + // 登录成功,将用户信息存入session + req.getSession().setAttribute("sysUser",loginUser); + // 登录成功 + // 将密码请空后,将用户信息响应给客户端 + loginUser.setUserPwd(""); + Map data =new HashMap<>(); + data.put("loginUser",loginUser); + result=Result.ok(data); + } + + WebUtil.writeJson(resp,result); + + } +``` + ++ router.js中,通过路由守卫控制只有登录状态下才可以进入showSchedule.vue + +``` javascript +import {createRouter,createWebHashHistory} from 'vue-router' + + +import pinia from '../pinia.js' +import {defineUser} from '../store/userStore.js' + +let sysUser = defineUser(pinia) + +import Login from '../components/Login.vue' +import Regist from '../components/Regist.vue' +import ShowScedule from '../components/ShowSchedule.vue' + +let router = createRouter({ + history:createWebHashHistory(), + routes:[ + { + path:"/", + component:Login + }, + { + path:"/login", + component:Login + }, + { + path:"/showSchedule", + component:ShowScedule + }, + { + path:"/regist", + component:Regist + } + ] +}) +/* 配置路由的前置守卫,在登录状态下才可以范文showSchedule.vue */ +router.beforeEach( (to,from,next) =>{ + // 如果是查看日程 + if(to.path=="/showSchedule"){ + // 如果尚未的登录 + if(sysUser.username == ''){ + alert("您尚未登录,请登录后再查看日程") + next("/login") + }else{ + // 已经登录 放行 + next() + } + // 其他资源 放行 + }else{ + next() + } +}) +export default router +``` + + + +### 12.2 显示所有日程数据 + ++ ShowSchedule.vue中向后端发送异步请求查询数据并展示 + +``` html + + + + + + +``` + ++ SysScheduleController中查询数据并响应json + +``` java +package com.atguigu.schedule.controller; + +import com.atguigu.schedule.common.Result; +import com.atguigu.schedule.pojo.SysSchedule; +import com.atguigu.schedule.service.SysScheduleService; +import com.atguigu.schedule.service.impl.SysScheduleServiceImpl; +import com.atguigu.schedule.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@WebServlet("/schedule/*") +public class SysScheduleController extends BaseController{ + private SysScheduleService scheduleService =new SysScheduleServiceImpl(); + /** + * 查询所有日程接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void findAllSchedule(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + int uid = Integer.parseInt(req.getParameter("uid")); + // 调用服务层方法,查询所有日程 + List itemList = scheduleService.findItemListByUid(uid); + // 将日程信息装入result,转换JSON给客户端 + Map data =new HashMap<>(); + data.put("itemList",itemList); + WebUtil.writeJson(resp,Result.ok(data)); + } +} + +``` + ++ SysScheduleService接口和实现类代码 + +``` java +package com.atguigu.schedule.service; +import com.atguigu.schedule.pojo.SysSchedule; +import java.util.List; +public interface SysScheduleService { + List findItemListByUid(int uid); +} + +// ------------------------------------------------ +package com.atguigu.schedule.service.impl; +import com.atguigu.schedule.dao.SysScheduleDao; +import com.atguigu.schedule.dao.impl.SysScheduleDaoImpl; +import com.atguigu.schedule.pojo.SysSchedule; +import com.atguigu.schedule.service.SysScheduleService; +import java.util.List; +public class SysScheduleServiceImpl implements SysScheduleService { + private SysScheduleDao scheduleDao =new SysScheduleDaoImpl(); + @Override + public List findItemListByUid(int uid) { + return scheduleDao.findItemListByUid(uid); + } +} +``` + ++ SysScheduleDao接口和实现类代码 + +``` java +package com.atguigu.schedule.dao; +import com.atguigu.schedule.pojo.SysSchedule; +import java.util.List; +public interface SysScheduleDao { + List findItemListByUid(int uid); +} +//----------------------------------------------------------- +package com.atguigu.schedule.dao.impl; +import com.atguigu.schedule.dao.BaseDao; +import com.atguigu.schedule.dao.SysScheduleDao; +import com.atguigu.schedule.pojo.SysSchedule; +import java.util.List; +public class SysScheduleDaoImpl extends BaseDao implements SysScheduleDao { + @Override + public List findItemListByUid(int uid) { + String sql ="select sid,uid,title, completed from sys_schedule where uid = ? "; + return baseQuery(SysSchedule.class,sql,uid); + } +} +``` + +### 12.3 增加和保存日程数据 + ++ ShowSchedule.vue下,为增加和修改按钮绑定事件 + +``` html + + + + + + +``` + ++ SysScheduleController处理 新增和保存修改业务处理接口 + +``` java +package com.atguigu.schedule.controller; + +import com.atguigu.schedule.common.Result; +import com.atguigu.schedule.pojo.SysSchedule; +import com.atguigu.schedule.service.SysScheduleService; +import com.atguigu.schedule.service.impl.SysScheduleServiceImpl; +import com.atguigu.schedule.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@WebServlet("/schedule/*") +public class SysScheduleController extends BaseController{ + + private SysScheduleService scheduleService =new SysScheduleServiceImpl(); + /** + * 向数据库中增加一个新的默认数据的方法 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void addDefaultSchedule(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + int uid = Integer.parseInt(req.getParameter("uid")); + // 调用服务层方法,为当前用户新增一个默认空数据 + scheduleService.addDefault(uid); + + WebUtil.writeJson(resp,Result.ok(null)); + + } + + + /** + * 更新日程业务接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void updateSchedule(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + SysSchedule sysSchedule = WebUtil.readJson(req, SysSchedule.class); + // 调用服务层方法,更新数据 + scheduleService.updateSchedule(sysSchedule); + + // 响应成功 + WebUtil.writeJson(resp,Result.ok(null)); + } +} + +``` + ++ SysScheduleService接口和实现类处理业务逻辑 + +``` java +package com.atguigu.schedule.service; +import com.atguigu.schedule.pojo.SysSchedule; +import java.util.List; +public interface SysScheduleService { + Integer addDefault(int uid); + Integer updateSchedule(SysSchedule sysSchedule); +} +// ---------------------------------------------------------- +package com.atguigu.schedule.service.impl; + +import com.atguigu.schedule.dao.SysScheduleDao; +import com.atguigu.schedule.dao.impl.SysScheduleDaoImpl; +import com.atguigu.schedule.pojo.SysSchedule; +import com.atguigu.schedule.service.SysScheduleService; + +import java.util.List; + +public class SysScheduleServiceImpl implements SysScheduleService { + private SysScheduleDao scheduleDao =new SysScheduleDaoImpl(); + @Override + public Integer addDefault(int uid) { + return scheduleDao.addDefault(uid); + } + + @Override + public Integer updateSchedule(SysSchedule sysSchedule) { + return scheduleDao.updateSchedule(sysSchedule); + } +} +``` + ++ SysScheduleDao接口和实现类操作数据 + +``` java +package com.atguigu.schedule.dao; + +import com.atguigu.schedule.pojo.SysSchedule; + +import java.util.List; + +public interface SysScheduleDao { + Integer addDefault(int uid); + Integer updateSchedule(SysSchedule sysSchedule); +} +//------------------------------------------------- +package com.atguigu.schedule.dao.impl; + +import com.atguigu.schedule.dao.BaseDao; +import com.atguigu.schedule.dao.SysScheduleDao; +import com.atguigu.schedule.pojo.SysSchedule; + +import java.util.List; +public class SysScheduleDaoImpl extends BaseDao implements SysScheduleDao { + @Override + public Integer addDefault(int uid) { + String sql = "insert into sys_schedule value(default,?,'请输入日程',0)"; + return baseUpdate(sql,uid); + } + + @Override + public Integer updateSchedule(SysSchedule sysSchedule) { + String sql ="update sys_schedule set title = ? ,completed = ? where sid =?"; + return baseUpdate(sql,sysSchedule.getTitle(),sysSchedule.getCompleted(),sysSchedule.getSid()); + } +} + +``` + +### 12.5 删除日程数据 + ++ ShowSchedule.vue中,为删除按钮增加事件 + +``` html + + + + + + +``` + ++ SysScheduleController中添加删除业务接口 + +``` java +package com.atguigu.schedule.controller; + +import com.atguigu.schedule.common.Result; +import com.atguigu.schedule.pojo.SysSchedule; +import com.atguigu.schedule.service.SysScheduleService; +import com.atguigu.schedule.service.impl.SysScheduleServiceImpl; +import com.atguigu.schedule.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@WebServlet("/schedule/*") +public class SysScheduleController extends BaseController{ + + private SysScheduleService scheduleService =new SysScheduleServiceImpl(); + + /** + * 删除日程业务接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void removeSchedule(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 获取要删除的日程id + int sid = Integer.parseInt(req.getParameter("sid")); + // 调用服务层方法,删除日程 + scheduleService.removeSchedule(sid); + // 响应200 + WebUtil.writeJson(resp,Result.ok(null)); + } +} +``` + ++ SysScheduleService层处理删除业务的接口和实现类 + +``` java +package com.atguigu.schedule.service; + +import com.atguigu.schedule.pojo.SysSchedule; + +import java.util.List; + +public interface SysScheduleService { + Integer removeSchedule(int sid); +} +//------------------------------------------------------------------ +package com.atguigu.schedule.service.impl; + +import com.atguigu.schedule.dao.SysScheduleDao; +import com.atguigu.schedule.dao.impl.SysScheduleDaoImpl; +import com.atguigu.schedule.pojo.SysSchedule; +import com.atguigu.schedule.service.SysScheduleService; + +import java.util.List; + +public class SysScheduleServiceImpl implements SysScheduleService { + private SysScheduleDao scheduleDao =new SysScheduleDaoImpl(); + @Override + public Integer removeSchedule(int sid) { + return scheduleDao.removeBySid(sid); + } +} +``` + ++ SysScheduleDao操作数据库的接口和实现类 + +``` java +package com.atguigu.schedule.dao; + +import com.atguigu.schedule.pojo.SysSchedule; + +import java.util.List; + +public interface SysScheduleDao { + Integer removeBySid(int sid); +} +//--------------------------------------------------------- +package com.atguigu.schedule.dao.impl; + +import com.atguigu.schedule.dao.BaseDao; +import com.atguigu.schedule.dao.SysScheduleDao; +import com.atguigu.schedule.pojo.SysSchedule; + +import java.util.List; + +public class SysScheduleDaoImpl extends BaseDao implements SysScheduleDao { + @Override + public Integer removeBySid(int sid) { + String sql ="delete from sys_schedule where sid = ?"; + + return baseUpdate(sql,sid); + } +} + +``` + + + + + +## 十三、Element-plus组件库 + +### 13.1 Element-plus介绍 + +> Element Plus 是一套基于 Vue 3 的开源 UI 组件库,是由饿了么前端团队开发的升级版本 Element UI。Element Plus 提供了丰富的 UI 组件、易于使用的 API 接口和灵活的主题定制功能,可以帮助开发者快速构建高质量的 Web 应用程序。 + ++ Element Plus 支持按需加载,且不依赖于任何第三方 CSS 库,它可以轻松地集成到任何 Vue.js 项目中。Element Plus 的文档十分清晰,提供了各种组件的使用方法和示例代码,方便开发者快速上手。 + ++ Element Plus 目前已经推出了大量的常用 UI 组件,如按钮、表单、表格、对话框、选项卡等,此外还提供了一些高级组件,如日期选择器、时间选择器、级联选择器、滑块、颜色选择器等。这些组件具有一致的设计和可靠的代码质量,可以为开发者提供稳定的使用体验。 + ++ 与 Element UI 相比,Element Plus 采用了现代化的技术架构和更加先进的设计理念,同时具备更好的性能和更好的兼容性。Element Plus 的更新迭代也更加频繁,可以为开发者提供更好的使用体验和更多的功能特性。 + ++ Element Plus 可以在支持 [ES2018](https://caniuse.com/?feats=mdn-javascript_builtins_regexp_dotall,mdn-javascript_builtins_regexp_lookbehind_assertion,mdn-javascript_builtins_regexp_named_capture_groups,mdn-javascript_builtins_regexp_property_escapes,mdn-javascript_builtins_symbol_asynciterator,mdn-javascript_functions_method_definitions_async_generator_methods,mdn-javascript_grammar_template_literals_template_literal_revision,mdn-javascript_operators_destructuring_rest_in_objects,mdn-javascript_operators_spread_spread_in_destructuring,promise-finally "ES2018") 和 [ResizeObserver](https://caniuse.com/resizeobserver "ResizeObserver") 的浏览器上运行。 如果您确实需要支持旧版本的浏览器,请自行添加 [Babel](https://babeljs.io/ "Babel") 和相应的 Polyfill + ++ 官网https://element-plus.gitee.io/zh-CN/ + ++ 由于 Vue 3 不再支持 IE11,Element Plus 也不再支持 IE 浏览器。 + +![](images/image_rdwmpig76n.png) + + + +### 13.2 Element-plus入门案例 + +> 1 准备vite项目 + +```shell +npm create vite // 注意选择 vue+typeScript +npm install +npm install vue-router@4 --save +npm install pinia +npm install axios +``` + +> 2 安装element-plus + +```shell +npm install element-plus +``` + +> 3 完整引入element-plus + ++ main.js + +```javascript +import { createApp } from 'vue' +//导入element-plus相关内容 +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' + +import App from './App.vue' + +const app = createApp(App) + +app.use(ElementPlus) +app.mount('#app') +``` + +> 4 入门案例 + ++ App.vue + +```html + + + + + + +``` + +> 5 启动测试 + +```shell +npm run dev +``` + +### 13.3 Element-plus常用组件 + + \ No newline at end of file diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/08_第八章 微头条项目开发.md b/语言/Java/大三前/朝花夕拾/尚硅谷/08_第八章 微头条项目开发.md new file mode 100644 index 0000000..4ec6bdf --- /dev/null +++ b/语言/Java/大三前/朝花夕拾/尚硅谷/08_第八章 微头条项目开发.md @@ -0,0 +1,3423 @@ + + +# 第八章 微头条项目开发 + +# 一 项目简介 + +## 1.1 微头条业务简介 + +> 微头条新闻发布和浏览平台,主要包含业务如下 + ++ 用户功能 + + 注册功能 + + 登录功能 ++ 头条新闻 + + 新闻的分页浏览 + + 通过标题关键字搜索新闻 + + 查看新闻详情 + + 新闻的修改和删除 ++ 权限控制 + + 用户只能修改和自己发布的头条新闻 + +## 1.2 技术栈介绍 + +> 前端技术栈 + ++ ES6作为基础JS语法 ++ nodejs用于运行环境 ++ npm用于项目依赖管理工具 ++ vite用于项目的构建架工具 ++ Vue3用于项目数据的渲染框架 ++ Axios用于前后端数据的交互 ++ Router用于页面的跳转 ++ Pinia用于存储用户的数据 ++ LocalStorage作为用户校验token的存储手段 ++ Element-Plus提供组件 + +> 后端技术栈 + ++ JAVA作为开发语言,版本为JDK17 ++ Tomcat作为服务容器,版本为10.1.7 ++ Mysql8用于项目存储数据 ++ Servlet用于控制层实现前后端数据交互 ++ JDBC用于实现数据的CURD ++ Druid用于提供数据源的连接池 ++ MD5用于用户密码的加密 ++ Jwt用于token的生成和校验 ++ Jackson用于转换JSON ++ Filter用于用户登录校验和跨域处理 ++ Lombok用于处理实体类 + + + +## 1.3 功能展示 + +> 头条首页信息搜索 + +![1687657562841](images/1687657562841.png) + +> 登录功能 + +![1683883374643](images/1683883374643.png) + +> 注册功能 + +![1683883394612](images/1683883394612.png) + +> 权限控制功能 + +![1687657603246](images/1687657603246.png) + +> 发布头条功能 + +![1683883660552](images/1683883660552.png) + +> 修改头条功能 + +![1683883695289](images/1683883695289.png) + +> 删除头条功能 + +![1683883724768](images/1683883724768.png) + +# 二 前端项目环境搭建 + ++ 解压前端项目代码并存放到磁盘的合适位置 + + + +![1683882754527](images/1683882754527.png) + ++ 使用vscode打开工程 + +![1683882823511](images/1683882823511.png) + + + ++ 进入项目后打开集成终端或者在src上右击选择在集成终端中打开 + +![1683882921502](images/1683882921502.png) + ++ 通过 npm run dev启动前端项目 + +![1683883090728](images/1683883090728.png) + +![1683883112782](images/1683883112782.png) + +# 三 后端项目环境搭建 + +## 3.1 数据库准备 + +> `news_users` 用户表 + +1683188408798 + +> `news_type` 新闻类型表 + +1683188444555 + +> `news_headline` 新闻信息表 + +1683188471933 + +> 数据库创建SQL + ++ 导入资料中的top_news.sql文件即可 + +## 3.2 MVC项目架构模式 + +> MVC(Model View Controller)是软件工程中的一种**`软件架构模式`**,它把软件系统分为**`模型`**、**`视图`**和**`控制器`**三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。 + ++ **M**:Model 模型层,具体功能如下 + 1. 存放和数据库对象的实体类以及一些用于存储非数据库表完整相关的VO对象 + 2. 存放一些对数据进行逻辑运算操作的的一些业务处理代码 + ++ **V**:View 视图层,具体功能如下 + 1. 存放一些视图文件相关的代码 html css js等 + 2. 在前后端分离的项目中,后端已经没有视图文件,该层次已经衍化成独立的前端项目 + ++ **C**:Controller 控制层,具体功能如下 + 1. 接收客户端请求,获得请求数据 + 2. 将准备好的数据响应给客户端 + +> MVC模式下,项目中的常见包 + ++ M: + 1. 实体类包(pojo /entity /bean) 专门存放和数据库对应的实体类和一些VO对象 + 2. 数据库访问包(dao/mapper) 专门存放对数据库不同表格CURD方法封装的一些类 + 3. 服务包(service) 专门存放对数据进行业务逻辑预算的一些类 + ++ C: + 1. 控制层包(controller) + ++ V: + 1. web目录下的视图资源 html css js img 等 + 2. 前端工程化后,在后端项目中已经不存在了 + +![1683363039636](images/1683363039636.png) + +## 3.3 搭建项目 + +### 3.3.1 创建WEB项目 + +![1683350231551](images/1683350231551.png) + +### 3.3.2 导入依赖 + +![1683351095131](images/1683351095131.png) + +### 3.3.3 准备包结构 + +![1683350275719](images/1683350275719.png) + ++ controller 控制层代码,主要由Servlet组成 ++ service 服务层代码,主要用于处理业务逻辑 ++ dao 数据访问层,主要用户定义对于各个表格的CURD的方法 ++ pojo 实体类层,主要用于存放和数据库对应的实体类以及一些VO对象 ++ util 工具类包,主要用存放一些工具类 ++ common 公共包,主要用户存放一些其他公共代码 ++ filters 过滤器包,专门用于存放一些过滤器 ++ test 测试代码包,专门用于定义一些测试的功能代码,上线前应该删掉,后期用maven可以自动处理掉 + +## 3.5 准备工具类 + +### 3.5.1 异步响应规范格式类 + ++ Result类 + +```java +package com.atguigu.headline.common; + +/** + * 全局统一返回结果类 + * + */ +public class Result { + // 返回码 + private Integer code; + // 返回消息 + private String message; + // 返回数据 + private T data; + public Result(){} + // 返回数据 + protected static Result build(T data) { + Result result = new Result(); + if (data != null) + result.setData(data); + return result; + } + public static Result build(T body, Integer code, String message) { + Result result = build(body); + result.setCode(code); + result.setMessage(message); + return result; + } + public static Result build(T body, ResultCodeEnum resultCodeEnum) { + Result result = build(body); + result.setCode(resultCodeEnum.getCode()); + result.setMessage(resultCodeEnum.getMessage()); + return result; + } + /** + * 操作成功 + * @param data baseCategory1List + * @param + * @return + */ + public static Result ok(T data){ + Result result = build(data); + return build(data, ResultCodeEnum.SUCCESS); + } + public Result message(String msg){ + this.setMessage(msg); + return this; + } + public Result code(Integer code){ + this.setCode(code); + return this; + } + public Integer getCode() { + return code; + } + public void setCode(Integer code) { + this.code = code; + } + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + public T getData() { + return data; + } + public void setData(T data) { + this.data = data; + } +} +``` + ++ ResultCodeEnum 枚举类 + +``` java +package com.atguigu.headline.common; +/** + * 统一返回结果状态信息类 + * + */ +public enum ResultCodeEnum { + + SUCCESS(200,"success"), + USERNAME_ERROR(501,"usernameError"), + PASSWORD_ERROR(503,"passwordError"), + NOTLOGIN(504,"notLogin"), + USERNAME_USED(505,"userNameUsed") + ; + + private Integer code; + private String message; + private ResultCodeEnum(Integer code, String message) { + this.code = code; + this.message = message; + } + public Integer getCode() { + return code; + } + public String getMessage() { + return message; + } +} + +``` + + + +### 3.5.2 MD5加密工具类 + + + +``` java +package com.atguigu.headline.util; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public final class MD5Util { + public static String encrypt(String strSrc) { + try { + char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + byte[] bytes = strSrc.getBytes(); + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(bytes); + bytes = md.digest(); + int j = bytes.length; + char[] chars = new char[j * 2]; + int k = 0; + for (int i = 0; i < bytes.length; i++) { + byte b = bytes[i]; + chars[k++] = hexChars[b >>> 4 & 0xf]; + chars[k++] = hexChars[b & 0xf]; + } + return new String(chars); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new RuntimeException("MD5加密出错!!+" + e); + } + } +} + +``` + +### 3.5.3 JDBCUtil连接池工具类 + + + +``` java +package com.atguigu.headline.util; + +import com.alibaba.druid.pool.DruidDataSourceFactory; + +import javax.sql.DataSource; +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +public class JDBCUtil { + private static ThreadLocal threadLocal =new ThreadLocal<>(); + + private static DataSource dataSource; + // 初始化连接池 + static{ + // 可以帮助我们读取.properties配置文件 + Properties properties =new Properties(); + InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"); + try { + properties.load(resourceAsStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try { + dataSource = DruidDataSourceFactory.createDataSource(properties); + } catch (Exception e) { + throw new RuntimeException(e); + } + + + } + /*1 向外提供连接池的方法*/ + public static DataSource getDataSource(){ + return dataSource; + } + + /*2 向外提供连接的方法*/ + public static Connection getConnection(){ + Connection connection = threadLocal.get(); + if (null == connection) { + try { + connection = dataSource.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + threadLocal.set(connection); + } + + return connection; + } + + + /*定义一个归还连接的方法 (解除和ThreadLocal之间的关联关系) */ + public static void releaseConnection(){ + Connection connection = threadLocal.get(); + if (null != connection) { + threadLocal.remove(); + // 把连接设置回自动提交的连接 + try { + connection.setAutoCommit(true); + // 自动归还到连接池 + connection.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } +} + +``` + ++ 添加jdbc.properties配置文件 + +``` properties +driverClassName=com.mysql.cj.jdbc.Driver +url=jdbc:mysql://localhost:3306/top_news +username=root +password=root +initialSize=5 +maxActive=10 +maxWait=1000 +``` + +### 3.5.4 JwtHelper工具类 + +``` java +package com.atguigu.headline.util; + +import com.alibaba.druid.util.StringUtils; +import io.jsonwebtoken.*; + +import java.util.Date; + +public class JwtHelper { + private static long tokenExpiration = 24*60*60*1000; + private static String tokenSignKey = "123456"; + + //生成token字符串 + public static String createToken(Long userId) { + String token = Jwts.builder() + + .setSubject("YYGH-USER") + .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) + .claim("userId", userId) + .signWith(SignatureAlgorithm.HS512, tokenSignKey) + .compressWith(CompressionCodecs.GZIP) + .compact(); + return token; + } + + //从token字符串获取userid + public static Long getUserId(String token) { + if(StringUtils.isEmpty(token)) return null; + Jws claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); + Claims claims = claimsJws.getBody(); + Integer userId = (Integer)claims.get("userId"); + return userId.longValue(); + } + + + + //判断token是否有效 + public static boolean isExpiration(String token){ + try { + boolean isExpire = Jwts.parser() + .setSigningKey(tokenSignKey) + .parseClaimsJws(token) + .getBody() + .getExpiration().before(new Date()); + //没有过期,有效,返回false + return isExpire; + }catch(Exception e) { + //过期出现异常,返回true + return true; + } + } +} + +``` + +### 3.5.5 JSON转换的WEBUtil工具类 + +``` java +package com.atguigu.headline.util; + +import com.atguigu.headline.common.Result; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.BufferedReader; +import java.io.IOException; +import java.text.SimpleDateFormat; + +public class WebUtil { + private static ObjectMapper objectMapper; + // 初始化objectMapper + static{ + objectMapper=new ObjectMapper(); + // 设置JSON和Object转换时的时间日期格式 + objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + } + // 从请求中获取JSON串并转换为Object + public static T readJson(HttpServletRequest request,Class clazz){ + T t =null; + BufferedReader reader = null; + try { + reader = request.getReader(); + StringBuffer buffer =new StringBuffer(); + String line =null; + while((line = reader.readLine())!= null){ + buffer.append(line); + } + + t= objectMapper.readValue(buffer.toString(),clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + return t; + } + // 将Result对象转换成JSON串并放入响应对象 + public static void writeJson(HttpServletResponse response, Result result){ + response.setContentType("application/json;charset=UTF-8"); + try { + String json = objectMapper.writeValueAsString(result); + response.getWriter().write(json); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} +``` + +## 3.6 准备各层的接口和实现类 + +### 3.6.1 准备实体类和VO对象 + +> NewsUser + +``` java +package com.atguigu.headline.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class NewsUser implements Serializable { + private Integer uid; + private String username; + private String userPwd; + private String nickName; +} +``` + +> NewsType + +``` java +package com.atguigu.headline.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class NewsType implements Serializable { + private Integer tid; + private String tname; +} +``` + +> NewsHeadline + +``` java +package com.atguigu.headline.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; +import java.util.Date; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class NewsHeadline implements Serializable { + private Integer hid; + private String title; + private String article; + private Integer type; + private Integer publisher; + private Integer pageViews; + private Date createTime; + private Date updateTime; + private Integer isDeleted; + +} +``` + +> HeadlineQueryVo + +``` java +package com.atguigu.headline.pojo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class HeadlineQueryVo implements Serializable { + private String keyWords; + private Integer type ; + private Integer pageNum; + private Integer pageSize; +} + +``` + +> HeadlinePageVo + +``` java +package com.atguigu.headline.pojo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class HeadlinePageVo implements Serializable { + private Integer hid; + private String title; + private Integer type; + private Integer pageViews; + private Long pastHours; + private Integer publisher; +} +``` + +> HeadlineDetailVo + +``` java +package com.atguigu.headline.pojo.vo; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class HeadlineDetailVo implements Serializable { + private Integer hid; + private String title; + private String article; + private Integer type; + private String typeName; + private Integer pageViews; + private Long pastHours; + private Integer publisher; + private String author; +} + +``` + +### 3.6.2 DAO层接口和实现类 + +![1683354561889](images/1683354561889.png) + +> BaseDao基础类,封装了公共的查询方法和公共的增删改方法 + ++ `注意,所有的Dao接口的实现类都要继承BaseDao` + +``` java +package com.atguigu.headline.dao; + + +import com.atguigu.headline.util.JDBCUtil; +import java.lang.reflect.Field; +import java.sql.*; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +public class BaseDao { + // 公共的查询方法 返回的是单个对象 + public T baseQueryObject(Class clazz, String sql, Object ... args) { + T t = null; + Connection connection = JDBCUtil.getConnection(); + PreparedStatement preparedStatement = null; + ResultSet resultSet = null; + int rows = 0; + try { + // 准备语句对象 + preparedStatement = connection.prepareStatement(sql); + // 设置语句上的参数 + for (int i = 0; i < args.length; i++) { + preparedStatement.setObject(i + 1, args[i]); + } + + // 执行 查询 + resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + t = (T) resultSet.getObject(1); + } + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (null != resultSet) { + try { + resultSet.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + if (null != preparedStatement) { + try { + preparedStatement.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + JDBCUtil.releaseConnection(); + } + return t; + } + // 公共的查询方法 返回的是对象的集合 + + public List baseQuery(Class clazz, String sql, Object ... args){ + List list =new ArrayList<>(); + Connection connection = JDBCUtil.getConnection(); + PreparedStatement preparedStatement=null; + ResultSet resultSet =null; + int rows = 0; + try { + // 准备语句对象 + preparedStatement = connection.prepareStatement(sql); + // 设置语句上的参数 + for (int i = 0; i < args.length; i++) { + preparedStatement.setObject(i+1,args[i]); + } + + // 执行 查询 + resultSet = preparedStatement.executeQuery(); + + ResultSetMetaData metaData = resultSet.getMetaData(); + int columnCount = metaData.getColumnCount(); + + // 将结果集通过反射封装成实体类对象 + while (resultSet.next()) { + // 使用反射实例化对象 + Object obj =clazz.getDeclaredConstructor().newInstance(); + + for (int i = 1; i <= columnCount; i++) { + String columnName = metaData.getColumnLabel(i); + Object value = resultSet.getObject(columnName); + // 处理datetime类型字段和java.util.Data转换问题 + if(value.getClass().equals(LocalDateTime.class)){ + value= Timestamp.valueOf((LocalDateTime) value); + } + Field field = clazz.getDeclaredField(columnName); + field.setAccessible(true); + field.set(obj,value); + } + + list.add((T)obj); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (null !=resultSet) { + try { + resultSet.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + if (null != preparedStatement) { + try { + preparedStatement.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + JDBCUtil.releaseConnection(); + } + return list; + } + + // 通用的增删改方法 + public int baseUpdate(String sql,Object ... args) { + // 获取连接 + Connection connection = JDBCUtil.getConnection(); + PreparedStatement preparedStatement=null; + int rows = 0; + try { + // 准备语句对象 + preparedStatement = connection.prepareStatement(sql); + // 设置语句上的参数 + for (int i = 0; i < args.length; i++) { + preparedStatement.setObject(i+1,args[i]); + } + + // 执行 增删改 executeUpdate + rows = preparedStatement.executeUpdate(); + // 释放资源(可选) + + + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + if (null != preparedStatement) { + try { + preparedStatement.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + } + JDBCUtil.releaseConnection(); + } + // 返回的是影响数据库记录数 + return rows; + } +} + +``` + +> dao层的所有接口 + +``` java +package com.atguigu.headline.dao; +public interface NewsHeadLineDao { + +} + +package com.atguigu.headline.dao; +public interface NewsTypeDao { + +} + + +package com.atguigu.headline.dao; +public interface NewsUserDao { + +} + +``` + +> dao层所有实现类 + +``` java +package com.atguigu.headline.dao.impl; +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + +} + +package com.atguigu.headline.dao.impl; +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsTypeDao; +public class NewsTypeDaoImpl extends BaseDao implements NewsTypeDao{ + +} + +package com.atguigu.headline.dao.impl; +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsUserDao; +public class NewsUserDaoImpl extends BaseDao implements NewsUserDao{ + +} +``` + +### 3.6.3 Service层接口和实现类 + +![1683354989263](images/1683354989263.png) + +> service层所有接口 + +``` java +package com.atguigu.headline.service; +public interface NewsHeadlineService { + +} + +package com.atguigu.headline.service; +public interface NewsTypeService { + List findAll(); +} + +package com.atguigu.headline.service; +public interface NewsUserService { + +} +``` + +> service层所有实现类 + +``` java +package com.atguigu.headline.service.impl; +import com.atguigu.headline.service.NewsHeadlineService; +public class NewsHeadlineServiceImpl implements NewsHeadlineService { +} + + +package com.atguigu.headline.service.impl; +import com.atguigu.headline.service.NewsTypeService; +public class NewsTypeServiceImpl implements NewsTypeService { + +} + +package com.atguigu.headline.service.impl; +import com.atguigu.headline.service.NewsUserService; +public class NewsUserServiceImpl implements NewsUserService { + +} + +``` + +### 3.6.4 Controller层接口和实现类 + +> BaseController 用于将路径关联到处理方法的基础控制器 + ++ `所有的Controller都要继承该类` + +``` java +package com.atguigu.headline.controller; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.lang.reflect.Method; + +public class BaseController extends HttpServlet { + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 响应的MIME类型和乱码问题 + resp.setContentType("application/json;charset=UTF-8"); + + String requestURI = req.getRequestURI(); + String[] split = requestURI.split("/"); + String methodName =split[split.length-1]; + // 通过反射获取要执行的方法 + Class clazz = this.getClass(); + try { + Method method=clazz.getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class); + // 设置方法可以访问 + method.setAccessible(true); + // 通过反射执行代码 + method.invoke(this,req,resp); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + } + } +} + +``` + +> 所有的Controller类 + +``` java +package com.atguigu.headline.controller; +import jakarta.servlet.annotation.WebServlet; +@WebServlet("/headline/*") +public class NewsHeadlineController extends BaseController { + +} + +package com.atguigu.headline.controller; +import jakarta.servlet.annotation.WebServlet; +@WebServlet("/type/*") +public class NewsTypeController { + +} + +package com.atguigu.headline.controller; +import jakarta.servlet.annotation.WebServlet; +@WebServlet("/user/*") +public class NewsUserController extends BaseController{ + +} + +package com.atguigu.headline.controller; +import jakarta.servlet.annotation.WebServlet; +@WebServlet("/portal/*") +public class PortalController extends BaseController{ + +} + +``` + +## 3.7 开发跨域CORS过滤器 + +### 3.7.1 什么是跨域 + +> 同源策略(Sameoriginpolicy)是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。**`同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号`** + +### 3.7.2 为什么会产生跨域 + +> 前后端分离模式下,客户端请求前端服务器获取视图资源,然后客户端自行向后端服务器获取数据资源,前端服务器的 协议,IP和端口和后端服务器很可能是不一样的,这样就产生了跨域 + +![1683364198087](images/1683364198087.png) + +### 3.7.3 如何解决跨域 + +> 前端项目代理模式处理 + +![1683365066926](images/1683365066926.png) + + + +> 后端跨域过滤器方式处理 + +![1683364436315](images/1683364436315.png) + ++ CrosFilter过滤器 + +``` java +package com.atguigu.headline.filters; + +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +@WebFilter("/*") +public class CrosFilter implements Filter { + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletResponse response = (HttpServletResponse) servletResponse; + HttpServletRequest request =(HttpServletRequest) servletRequest; + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With"); + // 非预检请求,放行即可,预检请求,则到此结束,不需要放行 + if(!request.getMethod().equalsIgnoreCase("OPTIONS")){ + filterChain.doFilter(servletRequest, servletResponse); + } + } +} +``` + + + ++ 未来我们使用框架,直接用一个@CrossOrigin 就可以解决跨域问题了 + +# 四 PostMan测试工具 + +## 4.1 什么是PostMan + ++ Postman是一个**`接口测试工具`**,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的各类HTTP请求,将请求数据发送至服务端,获取对应的响应结果, 从而验证响应中的结果数据是否和预期值相匹配;并确保开发人员能够及时处理接口中的bug,进而保证产品上线之后的稳定性和安全性。 它主要是用来模拟各种HTTP请求的(如:get/post/delete/put..等等),Postman与浏览器的区别在于有的浏览器不能输出Json格式,而Postman更直观接口返回的结果。 + +## 4.2 怎么安装PostMan + ++ 官网下载地址: https://www.getpostman.com ,或者使用资料中提供的安装包 ++ 安装过程简单,一路next即可 ++ 第一次启动postman 会要求输入用户名和密码,如果没有的话,关闭,再次启动就可以直接进入了 + +## 4.3 怎么使用PostMan + +> 启动PostMan后,创建一个collection,在该collection下专门存放和微头条项目相关的测试 + +1683385255826 + +> 创建完毕后,增加新的接口测试 + +1683385333460 + +> 填写要测试的接口相关的路径,参数,请求体内容等信息 + +1683385500897 + +> 测试完毕后,可以选择将该接口的测试进行保存,方便后续随时再次测试 + +1683385608824 + + + + + +# 五 登录注册功能 + +## 5.1 登录表单提交 + +![1687657661761](images/1687657661761.png) + +> 需求描述 + ++ 用户在客户端输入用户名密码并向后端提交,后端根据用户名和密码判断登录是否成功,用户有误或者密码有误响应不同的提示信息 + +> uri: + +``` http +user/login +``` + +> 请求方式: + +``` http +POST +``` + +> 请求参数 + +``` json +{ + "username":"zhangsan", //用户名 + "userPwd":"123456" //明文密码 +} +``` + +> 响应示例 + ++ 登录成功 + +``` json +{ + "code":"200", // 成功状态码 + "message":"success" // 成功状态描述 + "data":{ + "token":"... ..." // 用户id的token + } +} +``` + ++ 用户名有误 + +``` json +{ + "code":"501", + "message":"用户名有误" + "data":{} +} +``` + ++ 密码有误 + +``` json +{ + "code":"503", + "message":"密码有误" + "data":{} +} +``` + +> 后端代码 + ++ NewsUserController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.common.ResultCodeEnum; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.service.impl.NewsUserServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.MD5Util; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + + +@WebServlet("/user/*") +public class NewsUserController extends BaseController{ + + private NewsUserService newsUserService =new NewsUserServiceImpl(); + /** + * 登录验证 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + NewsUser newsUser = WebUtil.readJson(req, NewsUser.class); + + Result result =null; + NewsUser loginNewsUser =newsUserService.findByUserName(newsUser.getUsername()); + // 判断用户名 + if (null != loginNewsUser) { + // 判断密码 + if(loginNewsUser.getUserPwd().equals(MD5Util.encrypt(newsUser.getUserPwd()))){ + // 密码正确 + Map data =new HashMap<>(); + // 生成token口令 + String token = JwtHelper.createToken(loginNewsUser.getUid().longValue()); + // 封装数据map + data.put("token",token); + // 封装结果 + result=Result.ok(data); + }else{ + // 封装密码错误结果 + result=Result.build(null, ResultCodeEnum.PASSWORD_ERROR); + } + }else{ + // 封装用户名错误结果 + result=Result.build(null, ResultCodeEnum.USERNAME_ERROR); + } + // 响应结果 + WebUtil.writeJson(resp,result); + } +} +``` + ++ NewsUserService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsUser; + +public interface NewsUserService { + /** + * 根据用户名,获得查询用户的方法 + * @param username 要查询的用户名 + * @return 如果找到返回NewsUser对象,找不到返回null + */ + NewsUser findByUserName(String username); +} +``` + ++ NewsUserServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsUserDao; +import com.atguigu.headline.dao.impl.NewsUserDaoImpl; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsTypeService; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.util.MD5Util; + +public class NewsUserServiceImpl implements NewsUserService { + private NewsUserDao newsUserDao =new NewsUserDaoImpl(); + @Override + public NewsUser findByUserName(String username) { + return newsUserDao.findByUserName(username); + } +} +``` + ++ NewUserDao + +``` java +package com.atguigu.headline.dao; +import com.atguigu.headline.pojo.NewsUser; + +public interface NewsUserDao { + /** + * 根据用户名查询用户信息 + * @param username 要查询的用户名 + * @return 找到返回NewsUser对象,找不到返回null + */ + NewsUser findByUserName(String username); +} +``` + ++ NewsUserDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsUserDao; +import com.atguigu.headline.pojo.NewsUser; +import java.util.List; + +public class NewsUserDaoImpl extends BaseDao implements NewsUserDao { + + @Override + public NewsUser findByUserName(String username) { + // 准备SQL + String sql ="select uid,username,user_pwd userPwd ,nick_name nickName from news_user where username = ?"; + // 调用BaseDao公共查询方法 + List newsUserList = baseQuery(NewsUser.class, sql, username); + // 如果找到,返回集合中的第一个数据(其实就一个) + if (null != newsUserList && newsUserList.size()>0){ + return newsUserList.get(0); + } + return null; + } +} +``` + +## 5.2 根据token获取完整用户信息 + +> 需求描述 + ++ 客户端发送请求,提交token请求头,后端根据token请求头获取登录用户的详细信息并响应给客户端进行存储 + +> uri + +``` http +user/getUserInfo +``` + +> 请求方式 + +``` http +GET +``` + +> 请求头 + +``` json +token: ... ... +``` + +> 响应示例 + ++ 成功获取 + +``` JSON +{ + "code": 200, + "message": "success", + "data": { + "loginUser": { + "uid": 1, + "username": "zhangsan", + "userPwd": "", + "nickName": "张三" + } + } +} +``` + ++ 获取失败 + +``` json +{ + "code": 504, + "message": "notLogin", + "data": null +} +``` + +> 后端代码 + ++ NewsUserController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.common.ResultCodeEnum; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.service.impl.NewsUserServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.MD5Util; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + + +@WebServlet("/user/*") +public class NewsUserController extends BaseController{ + + private NewsUserService newsUserService =new NewsUserServiceImpl(); + + /** + * 接收token,根据token查询完整用户信息 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void getUserInfo(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String token = req.getHeader("token"); + Result result =Result.build(null,ResultCodeEnum.NOTLOGIN); + if(null!= token){ + if (!JwtHelper.isExpiration(token)) { + Integer uid = JwtHelper.getUserId(token).intValue(); + NewsUser newsUser =newsUserService.findByUid(uid); + newsUser.setUserPwd(""); + Map data =new HashMap<>(); + data.put("loginUser",newsUser); + result=Result.ok(data); + + } + } + WebUtil.writeJson(resp,result); + } +} +``` + ++ NewsUserService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsUser; + +public interface NewsUserService { + /** + * 根据用户id查询用户信息 + * @param uid 要查询的用户id + * @return 找到返回NewsUser对象,找不到返回null + */ + NewsUser findByUid(Integer uid); +} +``` + ++ NewsUserServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsUserDao; +import com.atguigu.headline.dao.impl.NewsUserDaoImpl; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsTypeService; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.util.MD5Util; + +public class NewsUserServiceImpl implements NewsUserService { + private NewsUserDao newsUserDao =new NewsUserDaoImpl(); + + @Override + public NewsUser findByUid(Integer uid) { + return newsUserDao.findByUid(uid); + } +} +``` + ++ NewUserDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsUser; + + +public interface NewsUserDao { + /** + * 根据用户id连接数据库查询用户信息 + * @param uid 要查询的用户id + * @return 找到返回NewsUser对象,找不到返回null + */ + NewsUser findByUid(Integer uid); +} +``` + ++ NewUserDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsUserDao; +import com.atguigu.headline.pojo.NewsUser; +import java.util.List; + +public class NewsUserDaoImpl extends BaseDao implements NewsUserDao { + @Override + public NewsUser findByUid(Integer uid) { + String sql ="select uid,username,user_pwd userPwd ,nick_name nickName from news_user where uid = ?"; + List newsUserList = baseQuery(NewsUser.class, sql, uid); + if (null != newsUserList && newsUserList.size()>0){ + return newsUserList.get(0); + } + return null; + } +} +``` + +## 5.3 注册时用户名占用校验 + +checkuserName + +> 需求说明 + ++ 用户在注册时输入用户名时,立刻将用户名发送给后端,后端根据用户名查询用户名是否可用并做出响应 + +> uri: + +``` http +user/checkUserName +``` + +> 请求方式: + +``` http +POST +``` + +> 请求参数 + +``` json +username=zhangsan +``` + +> 响应示例 + ++ 用户名校验通过 + +``` json +{ + "code":"200", + "message":"success" + "data":{} +} +``` + ++ 用户名占用 + +``` json +{ + "code":"505", + "message":"用户名占用" + "data":{} +} +``` + +> 后端代码 + ++ NewsUserController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.common.ResultCodeEnum; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.service.impl.NewsUserServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.MD5Util; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + + +@WebServlet("/user/*") +public class NewsUserController extends BaseController{ + + private NewsUserService newsUserService =new NewsUserServiceImpl(); + /** + * 注册时校验用户名是否被占用 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void checkUserName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String username = req.getParameter("username"); + NewsUser newsUser = newsUserService.findByUserName(username); + Result result=null; + if (null == newsUser){ + result=Result.ok(null); + }else{ + result=Result.build(null,ResultCodeEnum.USERNAME_USED); + } + WebUtil.writeJson(resp,result); + } +} +``` + +## 5.4 注册表单提交 + +regist + +> 需求说明 + ++ 客户端将新用户信息发送给服务端,服务端将新用户存入数据库,存入之前做用户名是否被占用校验,校验通过响应成功提示,否则响应失败提示 + + +> uri: + +``` http +user/regist +``` + +> 请求方式: + +``` http +POST +``` + +> 请求参数 + +``` json +{ + "username":"zhangsan", + "userPwd":"123456", + "nickName":"张三" +} +``` + +> 响应示例 + ++ 注册成功 + +``` json +{ + "code":"200", + "message":"success" + "data":{} +} +``` + ++ 用户名占用 + +``` json +{ + "code":"505", + "message":"用户名占用" + "data":{} +} +``` + +> 后端代码 + ++ NewsUserController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.common.ResultCodeEnum; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.service.impl.NewsUserServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.MD5Util; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + + +@WebServlet("/user/*") +public class NewsUserController extends BaseController{ + + private NewsUserService newsUserService =new NewsUserServiceImpl(); + + /** + * 注册功能接口 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + NewsUser newsUser = WebUtil.readJson(req, NewsUser.class); + NewsUser usedUser = newsUserService.findByUserName(newsUser.getUsername()); + Result result=null; + if (null == usedUser){ + newsUserService.registUser(newsUser); + result=Result.ok(null); + }else{ + result=Result.build(null,ResultCodeEnum.USERNAME_USED); + } + WebUtil.writeJson(resp,result); + } +} +``` + ++ NewsUserService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsUser; + +public interface NewsUserService { + + /** + * 注册用户信息,注册成功返回大于0的整数,失败返回0 + * @param newsUser + * @return + */ + int registUser(NewsUser newsUser); +} +``` + ++ NewsUserServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsUserDao; +import com.atguigu.headline.dao.impl.NewsUserDaoImpl; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsTypeService; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.util.MD5Util; + +public class NewsUserServiceImpl implements NewsUserService { + @Override + public int registUser(NewsUser newsUser) { + // 密码明文转密文 + newsUser.setUserPwd(MD5Util.encrypt(newsUser.getUserPwd())); + // 存入数据库 + return newsUserDao.insertNewsUser(newsUser); + } +} +``` + ++ NewUserDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsUser; + + +public interface NewsUserDao { + /** + * 将用户信息存入数据库 + * @param newsUser + * @return + */ + int insertNewsUser(NewsUser newsUser); +} +``` + ++ NewUserDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsUserDao; +import com.atguigu.headline.pojo.NewsUser; +import java.util.List; + +public class NewsUserDaoImpl extends BaseDao implements NewsUserDao { + @Override + public int insertNewsUser(NewsUser newsUser) { + String sql ="insert into news_user values(DEFAULT,?,?,?)"; + return baseUpdate(sql,newsUser.getUsername(),newsUser.getUserPwd(),newsUser.getNickName()); + } +} +``` + +# 六 头条首页功能 + +## 6.1 查询所有头条分类 + +![1684890693363](images/1684890693363.png) + +> 需求说明 + ++ 进入新闻首页,查询所有分类并动态展示新闻类别栏位 + +> uri: + +``` http +portal/findAllTypes +``` + +> 请求方式 + +``` http +GET +``` + +> 请求参数 + +``` JSON +无 +``` + +> 响应示例 + +``` JSON +{ + "code":"200", + "message":"OK" + "data": + [ + { + "tid":"1", + "tname":"新闻" + }, + { + "tid":"2", + "tname":"体育" + }, + { + "tid":"3", + "tname":"娱乐" + }, + { + "tid":"4", + "tname":"科技" + }, + { + "tid":"5", + "tname":"其他" + } + ] + +} + +``` + +> 后端代码 + ++ PortalController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsType; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.NewsTypeService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.service.impl.NewsTypeServiceImpl; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@WebServlet("/portal/*") +public class PortalController extends BaseController{ + + private NewsHeadlineService headlineService=new NewsHeadlineServiceImpl(); + private NewsTypeService newsTypeService=new NewsTypeServiceImpl(); + /** + * 查询所有新闻类型 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void findAllTypes(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + List newsTypeList =newsTypeService.findAll(); + WebUtil.writeJson(resp,Result.ok(newsTypeList)); + } +} +``` + ++ NewsTypeService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsType; + +import java.util.List; + +public interface NewsTypeService { + /** + * 查询全部新闻类型 + * @return + */ + List findAll(); +} + +``` + ++ NewsTypeServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsTypeDao; +import com.atguigu.headline.dao.impl.NewsTypeDaoImpl; +import com.atguigu.headline.pojo.NewsType; +import com.atguigu.headline.service.NewsTypeService; + +import java.util.List; + +public class NewsTypeServiceImpl implements NewsTypeService { + private NewsTypeDao newsTypeDao =new NewsTypeDaoImpl(); + @Override + public List findAll() { + return newsTypeDao.findAll(); + } +} +``` + ++ NewUserDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsType; + +import java.util.List; + +public interface NewsTypeDao { + /** + * 从数据库中查询全部新闻类型 + * @return + */ + List findAll(); +} + +``` + ++ NewsTypeDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsTypeDao; +import com.atguigu.headline.pojo.NewsType; + +import java.util.List; + +public class NewsTypeDaoImpl extends BaseDao implements NewsTypeDao { + @Override + public List findAll() { + String sql ="select tid,tname from news_type"; + return baseQuery(NewsType.class, sql); + } +} +``` + +## 6.2 分页带条件查询所有头条 + +![1684890943094](images/1684890943094.png) + +> 需求说明 + ++ 客户端向服务端发送查询关键字,新闻类别,页码数,页大小 ++ 服务端根据条件搜索分页信息,返回含页码数,页大小,总页数,总记录数,当前页数据等信息,并根据时间降序,浏览量降序排序 + +> uri: + +``` http +portal/findNewsPage +``` + +> 请求方式: + +``` http +POST +``` + +> 请求参数: + +``` json +{ + "keyWords":"马斯克", // 搜索标题关键字 + "type":0, // 新闻类型 + "pageNum":1, // 页码数 + "pageSize":"10" // 页大小 +} +``` + +> 响应示例: + +``` json +{ + "code":"200", + "message":"success" + "data":{ + "pageInfo":{ + "pageData":[ // 本页的数据 + { + "hid":"1", // 新闻id + "title":"尚硅谷宣布 ... ...", // 新闻标题 + "type":"1", // 新闻所属类别编号 + "pageViews":"40", // 新闻浏览量 + "pastHours":"3" , // 发布时间已过小时数 + "publisher":"1" // 发布用户ID + }, + { + "hid":"1", // 新闻id + "title":"尚硅谷宣布 ... ...", // 新闻标题 + "type":"1", // 新闻所属类别编号 + "pageViews":"40", // 新闻浏览量 + "pastHours":"3", // 发布时间已过小时数 + "publisher":"1" // 发布用户ID + }, + { + "hid":"1", // 新闻id + "title":"尚硅谷宣布 ... ...", // 新闻标题 + "type":"1", // 新闻所属类别编号 + "pageViews":"40", // 新闻浏览量 + "pastHours":"3", // 发布时间已过小时数 + "publisher":"1" // 发布用户ID + } + ], + "pageNum":1, //页码数 + "pageSize":10, // 页大小 + "totalPage":20, // 总页数 + "totalSize":200 // 总记录数 + } + } +} +``` + +> 后端代码 + ++ PortalController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsType; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.NewsTypeService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.service.impl.NewsTypeServiceImpl; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@WebServlet("/portal/*") +public class PortalController extends BaseController{ + + private NewsHeadlineService headlineService=new NewsHeadlineServiceImpl(); + private NewsTypeService newsTypeService=new NewsTypeServiceImpl(); + /** + * 分页带条件查询新闻 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void findNewsPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + HeadlineQueryVo headLineQueryVo = WebUtil.readJson(req, HeadlineQueryVo.class); + // 查询分页五项数据 + Map pageInfo =headlineService.findPage(headLineQueryVo); + // 将分页五项数据放入PageInfoMap + Map pageInfoMap=new HashMap<>(); + pageInfoMap.put("pageInfo",pageInfo); + // 响应JSON + WebUtil.writeJson(resp, Result.ok(pageInfoMap)); + } +} +``` + ++ NewsHeadlineService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; +import java.util.Map; + +public interface NewsHeadlineService { + /** + * 分页查询头条新闻方法 + * @param headLineQueryVo + * @return + */ + Map findPage(HeadlineQueryVo headLineQueryVo); +} +``` + ++ NewsHeadlineServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.dao.impl.NewsHeadlineDaoImpl; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewsHeadlineServiceImpl implements NewsHeadlineService { + private NewsHeadLineDao newsHeadLineDao =new NewsHeadlineDaoImpl(); + + @Override + public Map findPage(HeadlineQueryVo headLineQueryVo) { + // 准备一个map,用于装分页的五项数据 + Map pageInfo =new HashMap<>(); + // 分页查询本页数据 + List pageData =newsHeadLineDao.findPageList(headLineQueryVo); + // 分页查询满足记录的总数据量 + int totalSize = newsHeadLineDao.findPageCount(headLineQueryVo); + // 页大小 + int pageSize =headLineQueryVo.getPageSize(); + // 总页码数 + int totalPage=totalSize%pageSize == 0 ? totalSize/pageSize : totalSize/pageSize+1; + // 当前页码数 + int pageNum= headLineQueryVo.getPageNum(); + pageInfo.put("pageData",pageData); + pageInfo.put("pageNum",pageNum); + pageInfo.put("pageSize",pageSize); + pageInfo.put("totalPage",totalPage); + pageInfo.put("totalSize",totalSize); + + + return pageInfo; + } +} +``` + ++ NewsHeadLineDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; + +public interface NewsHeadLineDao { + /** + * 根据查询条件,查询满足条件的记录数 + * @param headLineQueryVo + * @return + */ + int findPageCount(HeadlineQueryVo headLineQueryVo); + + /** + * 根据查询条件,查询当前页数据 + * @param headLineQueryVo + * @return + */ + List findPageList(HeadlineQueryVo headLineQueryVo); +} +``` + ++ NewsHeadlineDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.LinkedList; +import java.util.List; + +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + + @Override + public int findPageCount(HeadlineQueryVo headLineQueryVo) { + // 拼接动态 SQL,拼接参数 + List args =new LinkedList<>(); + String sql="select count(1) from news_headline where is_deleted=0 "; + StringBuilder sqlBuffer =new StringBuilder(sql) ; + String keyWords = headLineQueryVo.getKeyWords(); + //判断并动态拼接条件 + if (null != keyWords && keyWords.length()>0){ + sqlBuffer.append("and title like ? "); + args.add("%"+keyWords+"%"); + } + // 判断并动态拼接条件 + Integer type = headLineQueryVo.getType(); + if(null != type && type != 0){ + sqlBuffer.append("and type = ? "); + args.add(type); + } + + // 参数转数组 + Object[] argsArr = args.toArray(); + System.out.println(sqlBuffer.toString()); + Long totalSize = baseQueryObject(Long.class, sqlBuffer.toString(), argsArr); + // 返回数据 + return totalSize.intValue(); + } + + @Override + public List findPageList(HeadlineQueryVo headLineQueryVo) { + // 拼接动态 SQL,拼接参数 + List args =new LinkedList<>(); + String sql="select hid,title,type,page_views pageViews,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,publisher from news_headline where is_deleted=0 "; + StringBuilder sqlBuffer =new StringBuilder(sql) ; + String keyWords = headLineQueryVo.getKeyWords(); + if (null != keyWords && keyWords.length()>0){ + sqlBuffer.append("and title like ? "); + args.add("%"+keyWords+"%"); + } + Integer type = headLineQueryVo.getType(); + if(null != type && type != 0){ + sqlBuffer.append("and type = ? "); + args.add(type); + } + + sqlBuffer.append("order by pastHours , page_views desc "); + sqlBuffer.append("limit ? , ?"); + args.add((headLineQueryVo.getPageNum()-1)*headLineQueryVo.getPageSize()); + args.add(headLineQueryVo.getPageSize()); + + // 参数转数组 + Object[] argsArr = args.toArray(); + System.out.println(sqlBuffer.toString()); + List pageData = baseQuery(HeadlinePageVo.class, sqlBuffer.toString(), argsArr); + + return pageData; + } +} +``` + +## 6.3 查看头条详情 + +1684891013180 + +![1684891029981](images/1684891029981.png) + +> 需求说明 + ++ 用户点击"查看全文"时,向服务端发送新闻id ++ 后端根据新闻id查询完整新闻文章信息并返回 ++ 后端要同时让新闻的浏览量+1 + +> uri + +``` http +portal/showHeadlineDetail +``` + +> 请求方式 + +``` http +POST +``` + +> 请求参数 + +``` json +hid=1 +``` + +> 响应示例 + +``` json +{ + "code":"200", + "message":"success", + "data":{ + "headline":{ + "hid":"1", // 新闻id + "title":"马斯克宣布 ... ...", // 新闻标题 + "article":"... ..." // 新闻正文 + "type":"1", // 新闻所属类别编号 + "typeName":"科技", // 新闻所属类别 + "pageViews":"40", // 新闻浏览量 + "pastHours":"3" , // 发布时间已过小时数 + "publisher":"1" , // 发布用户ID + "author":"张三" // 新闻作者 + } + } +} +``` + +> 后端代码 + ++ PortalController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsType; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.NewsTypeService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.service.impl.NewsTypeServiceImpl; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@WebServlet("/portal/*") +public class PortalController extends BaseController{ + + private NewsHeadlineService headlineService=new NewsHeadlineServiceImpl(); + private NewsTypeService newsTypeService=new NewsTypeServiceImpl(); + /** + * 查询单个新闻详情 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void showHeadlineDetail(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 获取要查询的详情新闻id + Integer hid =Integer.parseInt(req.getParameter("hid")); + + // 查询新闻详情vo + HeadlineDetailVo headlineDetailVo =headlineService.findHeadlineDetail(hid); + // 封装data内容 + Map data =new HashMap<>(); + data.put("headline",headlineDetailVo); + // 响应JSON + WebUtil.writeJson(resp,Result.ok(data)); + } +} +``` + ++ NewsHeadlineService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; +import java.util.Map; + +public interface NewsHeadlineService { + /** + * 根据头条id,显示头条详情 + * @param hid + * @return + */ + HeadlineDetailVo findHeadlineDetail(Integer hid); +} +``` + ++ NewsHeadlineServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.dao.impl.NewsHeadlineDaoImpl; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewsHeadlineServiceImpl implements NewsHeadlineService { + private NewsHeadLineDao newsHeadLineDao =new NewsHeadlineDaoImpl(); + @Override + public HeadlineDetailVo findHeadlineDetail(Integer hid) { + // 修改新闻信息浏览量+1 + newsHeadLineDao.increasePageViews(hid); + // 查询新闻详情 + return newsHeadLineDao.findHeadlineDetail(hid); + } +} +``` + ++ NewsHeadLineDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; + +public interface NewsHeadLineDao { + /** + * 多表查询新闻详情 + * @param hid + * @return + */ + HeadlineDetailVo findHeadlineDetail(Integer hid); + + int increasePageViews(Integer hid); +} +``` + ++ NewsHeadlineDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.LinkedList; +import java.util.List; + +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + @Override + public HeadlineDetailVo findHeadlineDetail(Integer hid) { + String sql ="select hid,title,article,type, tname typeName ,page_views pageViews,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,publisher,nick_name author from news_headline h left join news_type t on h.type = t.tid left join news_user u on h.publisher = u.uid where hid = ?"; + List headlineDetailVoList = baseQuery(HeadlineDetailVo.class, sql, hid); + if(null != headlineDetailVoList && headlineDetailVoList.size()>0) + return headlineDetailVoList.get(0); + return null; + } + + @Override + public int increasePageViews(Integer hid) { + String sql ="update news_headline set page_views = page_views +1 where hid =?"; + return baseUpdate(sql,hid); + } +} +``` + + + +# 七 头条发布修改和删除 + +## 7.1 登录校验 + +> 需求说明 + ++ 客户端在进入发布页前、发布新闻前、进入修改页前、修改前、删除新闻前先向服务端发送请求携带token请求头 ++ 后端接收token请求头后,校验用户登录是否过期并做响应 ++ 前端根据响应信息提示用户进入登录页还是进入正常业务页面 + +> uri + +``` http +user/checkLogin +``` + +> 请求方式 + +``` http +GET +``` + +> 请求参数 + +``` json +无 +``` + +> 请求头 + +``` JSON +token: ... ... +``` + +> 响应示例 + ++ 登录未过期 + +``` json +{ + "code":"200", + "message":"success", + "data":{} +} +``` + ++ 登录已过期 + +``` json +{ + "code":"504", + "message":"loginExpired", + "data":{} +} +``` + +> 后端代码 + ++ NewsUserController + +``` java +package com.atguigu.headline.controller; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.common.ResultCodeEnum; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.NewsUser; +import com.atguigu.headline.service.NewsUserService; +import com.atguigu.headline.service.impl.NewsUserServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.MD5Util; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + + +@WebServlet("/user/*") +public class NewsUserController extends BaseController{ + + private NewsUserService newsUserService =new NewsUserServiceImpl(); + /** + * 通过token检验用户登录是否过期 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void checkLogin(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String token = req.getHeader("token"); + Result result =Result.build(null,ResultCodeEnum.NOTLOGIN); + if(null!= token){ + if (!JwtHelper.isExpiration(token)) { + result=Result.ok(null); + } + } + WebUtil.writeJson(resp,result); + } +} +``` + ++ 登录校验过滤器 + +``` java +package com.atguigu.headline.filters; + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.common.ResultCodeEnum; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +public class LoginFilter implements Filter { + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request =(HttpServletRequest) servletRequest; + String token = request.getHeader("token"); + boolean flag =false; + // token不为空并且没过期 + if (null != token ){ + boolean expiration = JwtHelper.isExpiration(token); + if (!expiration ){ + flag=true; + } + } + if (flag){ + filterChain.doFilter(servletRequest,servletResponse); + }else{ + WebUtil.writeJson((HttpServletResponse) servletResponse, Result.build(null, ResultCodeEnum.NOTLOGIN)); + } + } +} +``` + ++ web.xml中配置登录校验过滤器 + +``` xml + + + loginFilter + com.atguigu.headline.filters.LoginFilter + + + loginFilter + /headline/* + +``` + +## 7.2 提交发布头条 + +![1683883660552](images/1683883660552.png) + +> 需求说明 + ++ 用户在客户端输入发布的新闻信息完毕后 ++ 发布前先请求后端的登录校验接口验证登录 ++ 登录通过则提交新闻信息 ++ 后端将新闻信息存入数据库 + +> uri + +``` http +headline/publish +``` + +> 请求方式 + +``` http +POST +``` + +> 请求头 + +``` json +token: ... ... +``` + +> 请求参数 + +``` json +{ + "title":"尚硅谷宣布 ... ...", // 文章标题 + "article":"... ...", // 文章内容 + "type":"1" // 文章类别 +} +``` + +> 响应示例 + ++ 发布成功 + +``` json +{ + "code":"200", + "message":"success", + "data":{} +} +``` + ++ 失去登录状态发布失败 + +``` json +{ + "code":"504", + "message":"loginExpired", + "data":{} +} +``` + +> 后端代码 + + ++ NewsHeadlineController + +``` java +package com.atguigu.headline.controller; + + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@WebServlet("/headline/*") +public class NewsHeadlineController extends BaseController { + + private NewsHeadlineService newsHeadlineService =new NewsHeadlineServiceImpl(); + /** + * 发布新闻 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void publish(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // 读取新闻信息 + NewsHeadline newsHeadline = WebUtil.readJson(req, NewsHeadline.class); + // 通过token获取发布者ID + String token = req.getHeader("token"); + Long userId = JwtHelper.getUserId(token); + newsHeadline.setPublisher(userId.intValue()); + // 将新闻存入数据库 + newsHeadlineService.addNewsHeadline(newsHeadline); + WebUtil.writeJson(resp,Result.ok(null)); + } +} +``` + ++ NewsHeadlineService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; +import java.util.Map; + +public interface NewsHeadlineService { + /** + * 新增头条 + * @param newsHeadline + * @return + */ + int addNewsHeadline(NewsHeadline newsHeadline); +} +``` + ++ NewsHeadlineServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.dao.impl.NewsHeadlineDaoImpl; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewsHeadlineServiceImpl implements NewsHeadlineService { + private NewsHeadLineDao newsHeadLineDao =new NewsHeadlineDaoImpl(); + public int addNewsHeadline(NewsHeadline newsHeadline) { + return newsHeadLineDao.addNewsHeadline(newsHeadline); + } +} +``` + ++ NewsHeadLineDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; + +public interface NewsHeadLineDao { + /** + * 头条存入数据库 + * @param newsHeadline + * @return + */ + int addNewsHeadline(NewsHeadline newsHeadline); +} +``` + ++ NewsHeadlineDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.LinkedList; +import java.util.List; + +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + @Override + public int addNewsHeadline(NewsHeadline newsHeadline) { + String sql = "insert into news_headline values(DEFAULT,?,?,?,?,0,NOW(),NOW(),0)"; + + return baseUpdate( + sql, + newsHeadline.getTitle(), + newsHeadline.getArticle(), + newsHeadline.getType(), + newsHeadline.getPublisher() + ); + } +} +``` + +## 7.3 修改头条回显 + +![1683883695289](images/1683883695289.png) + +> 需求说明 + ++ 前端先调用登录校验接口,校验登录是否过期 ++ 登录校验通过后 ,则根据新闻id查询新闻的完整信息并响应给前端 + +> uri + +``` http +headline/findHeadlineByHid +``` + +> 请求方式 + +``` http +POST +``` + +> 请求参数 + +``` json +hid=1 +``` + +> 响应示例 + ++ 查询成功 + +``` json +{ + "code":"200", + "message":"success", + "data":{ + "headline":{ + "hid":"1", + "title":"马斯克宣布", + "article":"... ... ", + "type":"2" + } + } +} +``` + +> 后端代码 + ++ NewsHeadlineController + +``` java +package com.atguigu.headline.controller; + + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@WebServlet("/headline/*") +public class NewsHeadlineController extends BaseController { + private NewsHeadlineService newsHeadlineService =new NewsHeadlineServiceImpl(); + /** + * 修改新闻回显 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void findHeadlineByHid(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + Integer hid = Integer.parseInt(req.getParameter("hid")); + NewsHeadline newsHeadline =newsHeadlineService.findHeadlineByHid(hid); + Map data =new HashMap<>(); + data.put("headline",newsHeadline); + WebUtil.writeJson(resp,Result.ok(data)); + + } +} +``` + ++ NewsHeadlineService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; +import java.util.Map; + +public interface NewsHeadlineService { + /** + * 根据新闻id查询单个新闻 + * @param hid + * @return + */ + NewsHeadline findHeadlineByHid(Integer hid); +} +``` + ++ NewsHeadlineServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.dao.impl.NewsHeadlineDaoImpl; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewsHeadlineServiceImpl implements NewsHeadlineService { + private NewsHeadLineDao newsHeadLineDao =new NewsHeadlineDaoImpl(); + @Override + public NewsHeadline findHeadlineByHid(Integer hid) { + return newsHeadLineDao.findHeadlineByHid(hid); + } +} +``` + ++ NewsHeadLineDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; + +public interface NewsHeadLineDao { + NewsHeadline findHeadlineByHid(Integer hid); +} +``` + ++ NewUserDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.LinkedList; +import java.util.List; + +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + + @Override + public NewsHeadline findHeadlineByHid(Integer hid) { + String sql ="select hid,title,article,type,publisher,page_views pageViews from news_headline where hid =?"; + List newsHeadlineList = baseQuery(NewsHeadline.class, sql, hid); + if(null != newsHeadlineList && newsHeadlineList.size()>0) + return newsHeadlineList.get(0); + return null; + } +} +``` + +## 7.4 保存修改 + +> 需求描述 + ++ 客户端将新闻信息修改后,提交前先请求登录校验接口校验登录状态 ++ 登录校验通过则提交修改后的新闻信息,后端接收并更新进入数据库 + +> uri + +``` http +headline/update +``` + +> 请求方式 + +``` http +POST +``` + +> 请求参数 + +``` JSON +{ + "hid":"1", + "title":"尚硅谷宣布 ... ...", + "article":"... ...", + "type":"2" +} +``` + +> 响应示例 + ++ 修改成功 + +``` json +{ + "code":"200", + "message":"success", + "data":{} +} +``` + ++ 修改失败 + +``` json +{ + "code":"504", + "message":"loginExpired", + "data":{} +} +``` + +> 后端代码 + ++ NewsHeadlineController + +``` java +package com.atguigu.headline.controller; + + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@WebServlet("/headline/*") +public class NewsHeadlineController extends BaseController { + private NewsHeadlineService newsHeadlineService =new NewsHeadlineServiceImpl(); + /** + * 更新新闻信息 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + NewsHeadline newsHeadline = WebUtil.readJson(req, NewsHeadline.class); + newsHeadlineService.updateNewsHeadline(newsHeadline); + WebUtil.writeJson(resp,Result.ok(null)); + } +} +``` + ++ NewsHeadlineService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; +import java.util.Map; + +public interface NewsHeadlineService { + int updateNewsHeadline(NewsHeadline newsHeadline); +} +``` + ++ NewsHeadlineServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.dao.impl.NewsHeadlineDaoImpl; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewsHeadlineServiceImpl implements NewsHeadlineService { + private NewsHeadLineDao newsHeadLineDao =new NewsHeadlineDaoImpl(); + @Override + public int updateNewsHeadline(NewsHeadline newsHeadline) { + return newsHeadLineDao.updateNewsHeadline(newsHeadline); + } +} +``` + ++ NewsHeadLineDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; + +public interface NewsHeadLineDao { + int updateNewsHeadline(NewsHeadline newsHeadline); +} +``` + ++ NewUserDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.LinkedList; +import java.util.List; + +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + @Override + public int updateNewsHeadline(NewsHeadline newsHeadline) { + String sql ="update news_headline set title = ?, article= ? , type =? , update_time = NOW() where hid = ? "; + return baseUpdate( + sql, + newsHeadline.getTitle(), + newsHeadline.getArticle(), + newsHeadline.getType(), + newsHeadline.getHid() + ); + } +} +``` + +## 7.5 删除头条 + +![1683883724768](images/1683883724768.png) + +> 需求说明 + ++ 将要删除的新闻id发送给服务端 ++ 服务端校验登录是否过期,未过期则直接删除,过期则响应登录过期信息 + +> uri + +``` http +headline/removeByHid +``` + +> 请求方式 + +``` http +POST +``` + +> 请求参数 + +``` json +hid=1 +``` + +> 响应示例 + ++ 删除成功 + +``` json +{ + "code":"200", + "message":"success", + "data":{} +} +``` + ++ 删除失败 + +``` json +{ + "code":"504", + "message":"loginExpired", + "data":{} + +} +``` + +> 后端代码 + ++ NewsHeadlineController + +``` java +package com.atguigu.headline.controller; + + +import com.atguigu.headline.common.Result; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.service.NewsHeadlineService; +import com.atguigu.headline.service.impl.NewsHeadlineServiceImpl; +import com.atguigu.headline.util.JwtHelper; +import com.atguigu.headline.util.WebUtil; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@WebServlet("/headline/*") +public class NewsHeadlineController extends BaseController { + private NewsHeadlineService newsHeadlineService =new NewsHeadlineServiceImpl(); + /** + * 删除新闻 + * @param req + * @param resp + * @throws ServletException + * @throws IOException + */ + protected void removeByHid(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + Integer hid = Integer.parseInt(req.getParameter("hid")); + newsHeadlineService.removeByHid(hid); + WebUtil.writeJson(resp,Result.ok(null)); + } +} +``` + ++ NewsHeadlineService + +``` java +package com.atguigu.headline.service; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; +import java.util.Map; + +public interface NewsHeadlineService { + int removeByHid(Integer hid); +} +``` + ++ NewsHeadlineServiceImpl + +``` java +package com.atguigu.headline.service.impl; + +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.dao.impl.NewsHeadlineDaoImpl; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; +import com.atguigu.headline.service.NewsHeadlineService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewsHeadlineServiceImpl implements NewsHeadlineService { + private NewsHeadLineDao newsHeadLineDao =new NewsHeadlineDaoImpl(); + @Override + public int removeByHid(Integer hid) { + return newsHeadLineDao.removeByHid(hid); + } +} +``` + ++ NewsHeadLineDao + +``` java +package com.atguigu.headline.dao; + +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.List; + +public interface NewsHeadLineDao { + int removeByHid(Integer hid); +} +``` + ++ NewsHeadlineDaoImpl + +``` java +package com.atguigu.headline.dao.impl; + +import com.atguigu.headline.dao.BaseDao; +import com.atguigu.headline.dao.NewsHeadLineDao; +import com.atguigu.headline.pojo.NewsHeadline; +import com.atguigu.headline.pojo.vo.HeadlineDetailVo; +import com.atguigu.headline.pojo.vo.HeadlinePageVo; +import com.atguigu.headline.pojo.vo.HeadlineQueryVo; + +import java.util.LinkedList; +import java.util.List; + +public class NewsHeadlineDaoImpl extends BaseDao implements NewsHeadLineDao{ + @Override + public int removeByHid(Integer hid) { + String sql ="update news_headline set is_deleted =1 , update_time =NOW() where hid = ? "; + return baseUpdate(sql,hid); + } +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/Tomcat.md b/语言/Java/大三前/朝花夕拾/尚硅谷/Tomcat.md new file mode 100644 index 0000000..82d4341 --- /dev/null +++ b/语言/Java/大三前/朝花夕拾/尚硅谷/Tomcat.md @@ -0,0 +1,19 @@ +## 一个标准的可发布的目录的结构 + +![image-20241230165354236](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20241230165354236.png) + +WEB-INF 是受保护的资源 浏览器通过url不可以直接访问目录 + +![image-20241230221649489](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20241230221649489.png) + +Serverlet是干什么的 + + + + + +## MVC设计模式 + +![image-20250102204606669](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250102204606669.png) + +![image-20250102205445379](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250102205445379.png) \ No newline at end of file diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1557672342250_1H8nt17MNz.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1557672342250_1H8nt17MNz.png new file mode 100644 index 0000000..afb282d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1557672342250_1H8nt17MNz.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1557672415271_EgyN-GdbWY.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1557672415271_EgyN-GdbWY.png new file mode 100644 index 0000000..01aa379 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1557672415271_EgyN-GdbWY.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681115424967.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681115424967.png new file mode 100644 index 0000000..09a9322 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681115424967.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681115460825.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681115460825.png new file mode 100644 index 0000000..a846744 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681115460825.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681175338788.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681175338788.png new file mode 100644 index 0000000..d8d4b95 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681175338788.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176136290.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176136290.png new file mode 100644 index 0000000..f83a627 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176136290.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176242960.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176242960.png new file mode 100644 index 0000000..40879fb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176242960.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176337725.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176337725.png new file mode 100644 index 0000000..43a53a1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176337725.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176383286.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176383286.png new file mode 100644 index 0000000..1a7ac2b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176383286.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176504817.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176504817.png new file mode 100644 index 0000000..085d0f5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176504817.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176635024.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176635024.png new file mode 100644 index 0000000..3c7f374 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176635024.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176763818.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176763818.png new file mode 100644 index 0000000..387de73 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176763818.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176815540.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176815540.png new file mode 100644 index 0000000..22b8a77 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681176815540.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177160318.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177160318.png new file mode 100644 index 0000000..f058f85 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177160318.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177186528.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177186528.png new file mode 100644 index 0000000..57c31f1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177186528.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177316138.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177316138.png new file mode 100644 index 0000000..dea8885 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681177316138.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681178113257.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681178113257.png new file mode 100644 index 0000000..86a7e91 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681178113257.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681179289089.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681179289089.png new file mode 100644 index 0000000..cf62c90 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681179289089.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180017304.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180017304.png new file mode 100644 index 0000000..0f28e64 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180017304.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180239241.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180239241.png new file mode 100644 index 0000000..45b76c0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180239241.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180699132.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180699132.png new file mode 100644 index 0000000..b1970ce Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681180699132.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181342911.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181342911.png new file mode 100644 index 0000000..5b33502 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181342911.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181399123.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181399123.png new file mode 100644 index 0000000..46f25bd Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181399123.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181558166.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181558166.png new file mode 100644 index 0000000..7ea9334 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181558166.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181668235.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181668235.png new file mode 100644 index 0000000..8aa991f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181668235.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181764764.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181764764.png new file mode 100644 index 0000000..bc69a56 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181764764.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181829641.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181829641.png new file mode 100644 index 0000000..a1411e3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181829641.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181884366.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181884366.png new file mode 100644 index 0000000..872c868 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181884366.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181975807.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181975807.png new file mode 100644 index 0000000..ebc28c0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681181975807.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681182451912.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681182451912.png new file mode 100644 index 0000000..887bf09 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681182451912.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681182819066.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681182819066.png new file mode 100644 index 0000000..758688d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681182819066.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681192888853.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681192888853.png new file mode 100644 index 0000000..448dd66 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681192888853.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681192907280.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681192907280.png new file mode 100644 index 0000000..1447d02 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681192907280.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681193247981.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681193247981.png new file mode 100644 index 0000000..ee16d21 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681193247981.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194349015.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194349015.png new file mode 100644 index 0000000..bed0006 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194349015.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194434091.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194434091.png new file mode 100644 index 0000000..d5cd2bc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194434091.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194504371.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194504371.png new file mode 100644 index 0000000..8654b45 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681194504371.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681195535127.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681195535127.png new file mode 100644 index 0000000..34b3c94 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681195535127.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681195890442.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681195890442.png new file mode 100644 index 0000000..351f70f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681195890442.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196233304.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196233304.png new file mode 100644 index 0000000..8935f8d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196233304.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196276582.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196276582.png new file mode 100644 index 0000000..5b4b85f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196276582.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196307844.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196307844.png new file mode 100644 index 0000000..f164233 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196307844.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196961386.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196961386.png new file mode 100644 index 0000000..a8bc272 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681196961386.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681197062594.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681197062594.png new file mode 100644 index 0000000..068891a Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681197062594.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681197299564.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681197299564.png new file mode 100644 index 0000000..c6e87a8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681197299564.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198068548.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198068548.png new file mode 100644 index 0000000..e927ca5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198068548.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198354039.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198354039.png new file mode 100644 index 0000000..8c43ea3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198354039.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198393831.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198393831.png new file mode 100644 index 0000000..54f5972 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198393831.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198448345.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198448345.png new file mode 100644 index 0000000..1e04c83 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198448345.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198540737.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198540737.png new file mode 100644 index 0000000..f0c9fb6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198540737.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198559213.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198559213.png new file mode 100644 index 0000000..f0c9fb6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681198559213.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199376475.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199376475.png new file mode 100644 index 0000000..0f920eb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199376475.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199471712.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199471712.png new file mode 100644 index 0000000..264fc17 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199471712.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199589613.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199589613.png new file mode 100644 index 0000000..dddbb90 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199589613.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199672580.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199672580.png new file mode 100644 index 0000000..b0f6ade Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681199672580.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200198741.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200198741.png new file mode 100644 index 0000000..fd3827b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200198741.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200358272.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200358272.png new file mode 100644 index 0000000..0f394b8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200358272.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200435834.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200435834.png new file mode 100644 index 0000000..69980ac Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200435834.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200467767.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200467767.png new file mode 100644 index 0000000..cae573c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200467767.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200487125.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200487125.png new file mode 100644 index 0000000..6ef0ea4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200487125.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200503798.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200503798.png new file mode 100644 index 0000000..8c55a93 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200503798.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200662087.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200662087.png new file mode 100644 index 0000000..cee9257 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681200662087.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681201322584.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681201322584.png new file mode 100644 index 0000000..7018d2b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681201322584.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681201553427.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681201553427.png new file mode 100644 index 0000000..00411c3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681201553427.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681202361429.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681202361429.png new file mode 100644 index 0000000..14a4fb4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681202361429.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681203591080.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681203591080.png new file mode 100644 index 0000000..dcf95d0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681203591080.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681203748017.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681203748017.png new file mode 100644 index 0000000..7177a90 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681203748017.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681204269702.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681204269702.png new file mode 100644 index 0000000..38a1b91 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681204269702.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260732580.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260732580.png new file mode 100644 index 0000000..ae87c86 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260732580.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260842005.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260842005.png new file mode 100644 index 0000000..79f1b95 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260842005.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260887708.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260887708.png new file mode 100644 index 0000000..a091f17 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260887708.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260937920.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260937920.png new file mode 100644 index 0000000..d712f18 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681260937920.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261311289.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261311289.png new file mode 100644 index 0000000..f30db5c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261311289.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261377875.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261377875.png new file mode 100644 index 0000000..5a3f295 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261377875.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261602297.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261602297.png new file mode 100644 index 0000000..20c11b5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261602297.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261830830.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261830830.png new file mode 100644 index 0000000..d4d2f11 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261830830.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261993904.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261993904.png new file mode 100644 index 0000000..fcb89ac Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681261993904.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681262535006.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681262535006.png new file mode 100644 index 0000000..03fb842 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681262535006.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681262585852.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681262585852.png new file mode 100644 index 0000000..6d1dc7c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681262585852.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681263227281.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681263227281.png new file mode 100644 index 0000000..2da0316 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681263227281.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681263265604.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681263265604.png new file mode 100644 index 0000000..c778e68 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681263265604.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681265611540.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681265611540.png new file mode 100644 index 0000000..fce4cca Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681265611540.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681266220955.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681266220955.png new file mode 100644 index 0000000..f0b6f87 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681266220955.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681267483366.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681267483366.png new file mode 100644 index 0000000..3e1b7e7 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681267483366.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681269953136.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681269953136.png new file mode 100644 index 0000000..39f55dc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681269953136.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681269970254.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681269970254.png new file mode 100644 index 0000000..4946071 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681269970254.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681270260741.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681270260741.png new file mode 100644 index 0000000..ee784ae Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681270260741.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681270974917.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681270974917.png new file mode 100644 index 0000000..0c7a8be Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681270974917.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681285904625.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681285904625.png new file mode 100644 index 0000000..b83f57e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681285904625.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287264843.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287264843.png new file mode 100644 index 0000000..c689b08 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287264843.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287540562.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287540562.png new file mode 100644 index 0000000..f44ade3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287540562.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287984473.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287984473.png new file mode 100644 index 0000000..4d2d45f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681287984473.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681288692792.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681288692792.png new file mode 100644 index 0000000..176dacc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681288692792.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681292306466.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681292306466.png new file mode 100644 index 0000000..29a92d5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681292306466.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681441674967.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681441674967.png new file mode 100644 index 0000000..9d09c94 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681441674967.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442513261.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442513261.png new file mode 100644 index 0000000..a9f6055 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442513261.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442778503.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442778503.png new file mode 100644 index 0000000..6742c93 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442778503.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442849940.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442849940.png new file mode 100644 index 0000000..a607ee2 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442849940.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442946756.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442946756.png new file mode 100644 index 0000000..9526076 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442946756.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442998407.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442998407.png new file mode 100644 index 0000000..057cb4a Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681442998407.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443038911.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443038911.png new file mode 100644 index 0000000..757dc0f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443038911.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443124315.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443124315.png new file mode 100644 index 0000000..7a52a22 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443124315.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443202115.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443202115.png new file mode 100644 index 0000000..aec6a49 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443202115.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443273573.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443273573.png new file mode 100644 index 0000000..3c6329f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443273573.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443314432.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443314432.png new file mode 100644 index 0000000..e5ed878 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681443314432.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681452257379.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681452257379.png new file mode 100644 index 0000000..3fd5fea Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681452257379.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681452377469.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681452377469.png new file mode 100644 index 0000000..88607eb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681452377469.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681453620343.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681453620343.png new file mode 100644 index 0000000..f66fec1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681453620343.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456086775.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456086775.png new file mode 100644 index 0000000..aad5f7d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456086775.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456161723.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456161723.png new file mode 100644 index 0000000..b5be076 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456161723.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456447284.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456447284.png new file mode 100644 index 0000000..4983727 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681456447284.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457611053.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457611053.png new file mode 100644 index 0000000..30a5617 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457611053.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457711914.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457711914.png new file mode 100644 index 0000000..3eddff6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457711914.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457800708.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457800708.png new file mode 100644 index 0000000..ca2965c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457800708.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457879937.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457879937.png new file mode 100644 index 0000000..38ebc04 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457879937.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457921094.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457921094.png new file mode 100644 index 0000000..6fa47ed Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681457921094.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458031957.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458031957.png new file mode 100644 index 0000000..0590b99 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458031957.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458177811.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458177811.png new file mode 100644 index 0000000..18ccee4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458177811.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458194939.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458194939.png new file mode 100644 index 0000000..3e96421 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458194939.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458273381.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458273381.png new file mode 100644 index 0000000..f1efaa6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458273381.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458343921.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458343921.png new file mode 100644 index 0000000..7bb2456 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458343921.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458393871.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458393871.png new file mode 100644 index 0000000..85ce576 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458393871.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458485837.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458485837.png new file mode 100644 index 0000000..db59cda Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458485837.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458599545.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458599545.png new file mode 100644 index 0000000..4abee05 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458599545.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458672258.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458672258.png new file mode 100644 index 0000000..39aa67b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458672258.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458857830.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458857830.png new file mode 100644 index 0000000..bc16c75 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458857830.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458897017.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458897017.png new file mode 100644 index 0000000..cc80534 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458897017.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458917073.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458917073.png new file mode 100644 index 0000000..b7c7fb7 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458917073.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458939400.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458939400.png new file mode 100644 index 0000000..b7c7fb7 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681458939400.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459007273.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459007273.png new file mode 100644 index 0000000..874029d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459007273.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459080873.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459080873.png new file mode 100644 index 0000000..d04cac9 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459080873.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459147133.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459147133.png new file mode 100644 index 0000000..34cacb0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681459147133.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461443278.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461443278.png new file mode 100644 index 0000000..a2414c1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461443278.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461513406.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461513406.png new file mode 100644 index 0000000..135ec0d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461513406.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461788411.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461788411.png new file mode 100644 index 0000000..8160d24 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461788411.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461846178.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461846178.png new file mode 100644 index 0000000..2e85b59 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461846178.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461881121.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461881121.png new file mode 100644 index 0000000..8e1f136 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461881121.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461923761.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461923761.png new file mode 100644 index 0000000..63482f4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681461923761.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462053127.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462053127.png new file mode 100644 index 0000000..10bc6d2 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462053127.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462179671.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462179671.png new file mode 100644 index 0000000..2058aa0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462179671.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462247973.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462247973.png new file mode 100644 index 0000000..0df2623 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462247973.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462523901.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462523901.png new file mode 100644 index 0000000..ade5f0b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462523901.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462584524.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462584524.png new file mode 100644 index 0000000..2daebf9 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462584524.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462621908.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462621908.png new file mode 100644 index 0000000..7d5b7ef Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462621908.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462626981.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462626981.png new file mode 100644 index 0000000..7d5b7ef Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462626981.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462645070.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462645070.png new file mode 100644 index 0000000..8b0dd73 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462645070.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462710108.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462710108.png new file mode 100644 index 0000000..b663de6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462710108.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462754191.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462754191.png new file mode 100644 index 0000000..3f50b8b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462754191.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462798933.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462798933.png new file mode 100644 index 0000000..ca86472 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681462798933.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463011546.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463011546.png new file mode 100644 index 0000000..3588d6d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463011546.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463049807.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463049807.png new file mode 100644 index 0000000..a451429 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463049807.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463212587.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463212587.png new file mode 100644 index 0000000..40b22a3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463212587.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463361795.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463361795.png new file mode 100644 index 0000000..0804edb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463361795.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463386274.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463386274.png new file mode 100644 index 0000000..1a29247 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463386274.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463481451.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463481451.png new file mode 100644 index 0000000..77a3489 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463481451.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463867295.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463867295.png new file mode 100644 index 0000000..3365249 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681463867295.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681464081226.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681464081226.png new file mode 100644 index 0000000..fcfa919 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681464081226.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681520068936.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681520068936.png new file mode 100644 index 0000000..0caa802 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681520068936.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681521240438.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681521240438.png new file mode 100644 index 0000000..adf0071 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681521240438.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522138051.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522138051.png new file mode 100644 index 0000000..226939f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522138051.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522600239.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522600239.png new file mode 100644 index 0000000..7245a02 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522600239.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522638617.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522638617.png new file mode 100644 index 0000000..4fda656 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522638617.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522962846.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522962846.png new file mode 100644 index 0000000..6fd589e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522962846.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522998417.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522998417.png new file mode 100644 index 0000000..513450b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681522998417.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681524200024.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681524200024.png new file mode 100644 index 0000000..efdfdf1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681524200024.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525012046.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525012046.png new file mode 100644 index 0000000..d58329d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525012046.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525347456.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525347456.png new file mode 100644 index 0000000..04a0bbc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525347456.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525384347.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525384347.png new file mode 100644 index 0000000..81f4cd3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525384347.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525742901.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525742901.png new file mode 100644 index 0000000..11ccde8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681525742901.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681544428055.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681544428055.png new file mode 100644 index 0000000..20c7a7f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681544428055.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681547333799.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681547333799.png new file mode 100644 index 0000000..92db658 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681547333799.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681550398774.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681550398774.png new file mode 100644 index 0000000..1a60414 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681550398774.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681699577344.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681699577344.png new file mode 100644 index 0000000..6a71153 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681699577344.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681717793500.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681717793500.png new file mode 100644 index 0000000..c33e9d3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681717793500.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681717880183.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681717880183.png new file mode 100644 index 0000000..723aaf5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681717880183.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718007772.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718007772.png new file mode 100644 index 0000000..abfb595 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718007772.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718299804.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718299804.png new file mode 100644 index 0000000..8d9940d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718299804.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718460738.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718460738.png new file mode 100644 index 0000000..566287f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718460738.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718676917.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718676917.png new file mode 100644 index 0000000..29a0161 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1681718676917.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682036233867.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682036233867.png new file mode 100644 index 0000000..ac6aa67 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682036233867.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682299663047.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682299663047.png new file mode 100644 index 0000000..5b8786e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682299663047.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682302307081.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682302307081.png new file mode 100644 index 0000000..b7cf1d5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682302307081.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682303205351.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682303205351.png new file mode 100644 index 0000000..036eaa8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682303205351.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682321228643.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682321228643.png new file mode 100644 index 0000000..12bb60b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682321228643.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682322389710.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682322389710.png new file mode 100644 index 0000000..60a60cd Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682322389710.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682322460011.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682322460011.png new file mode 100644 index 0000000..c0a83c4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682322460011.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682323740343.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682323740343.png new file mode 100644 index 0000000..96af306 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682323740343.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325615922.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325615922.png new file mode 100644 index 0000000..925c112 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325615922.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325817829.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325817829.png new file mode 100644 index 0000000..b43677c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325817829.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325946725.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325946725.png new file mode 100644 index 0000000..2ef0ecb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682325946725.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682326229063.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682326229063.png new file mode 100644 index 0000000..671cdaf Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682326229063.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682326867396.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682326867396.png new file mode 100644 index 0000000..887c76d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682326867396.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385863928.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385863928.png new file mode 100644 index 0000000..51c7535 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385863928.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385870660.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385870660.png new file mode 100644 index 0000000..51c7535 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385870660.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385997927.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385997927.png new file mode 100644 index 0000000..f4e8ceb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682385997927.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386110151.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386110151.png new file mode 100644 index 0000000..588b7c2 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386110151.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386298048.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386298048.png new file mode 100644 index 0000000..4766abf Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386298048.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386374464.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386374464.png new file mode 100644 index 0000000..5b82d22 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386374464.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386551684.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386551684.png new file mode 100644 index 0000000..2911f8f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386551684.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386611945.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386611945.png new file mode 100644 index 0000000..e6f4282 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682386611945.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387194348.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387194348.png new file mode 100644 index 0000000..b3cec06 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387194348.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387258428.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387258428.png new file mode 100644 index 0000000..2a35311 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387258428.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387349916.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387349916.png new file mode 100644 index 0000000..6f41627 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387349916.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387412704.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387412704.png new file mode 100644 index 0000000..8d3377c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387412704.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387836615.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387836615.png new file mode 100644 index 0000000..4f73286 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387836615.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387857587.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387857587.png new file mode 100644 index 0000000..00ad577 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682387857587.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388026978.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388026978.png new file mode 100644 index 0000000..9148b22 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388026978.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388204239.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388204239.png new file mode 100644 index 0000000..52150ab Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388204239.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388599014.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388599014.png new file mode 100644 index 0000000..0b0aa69 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682388599014.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389063225.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389063225.png new file mode 100644 index 0000000..8bfee85 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389063225.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389263627.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389263627.png new file mode 100644 index 0000000..bd281fc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389263627.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389299826.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389299826.png new file mode 100644 index 0000000..a352a3c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389299826.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389317234.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389317234.png new file mode 100644 index 0000000..a352a3c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682389317234.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682390999417.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682390999417.png new file mode 100644 index 0000000..d1d950b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682390999417.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411089082.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411089082.png new file mode 100644 index 0000000..9c1f89e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411089082.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411455146.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411455146.png new file mode 100644 index 0000000..bf25746 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411455146.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411522695.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411522695.png new file mode 100644 index 0000000..20a0e0e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411522695.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411576377.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411576377.png new file mode 100644 index 0000000..20a0e0e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411576377.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411757748.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411757748.png new file mode 100644 index 0000000..4b3983e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682411757748.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682413051408.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682413051408.png new file mode 100644 index 0000000..c858d89 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682413051408.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682470547651.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682470547651.png new file mode 100644 index 0000000..dc30f37 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682470547651.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682470652577.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682470652577.png new file mode 100644 index 0000000..7d1d8cc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682470652577.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471183183.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471183183.png new file mode 100644 index 0000000..46fd76b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471183183.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471232199.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471232199.png new file mode 100644 index 0000000..93f651f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471232199.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471342313.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471342313.png new file mode 100644 index 0000000..2f863ee Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682471342313.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476206286.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476206286.png new file mode 100644 index 0000000..c4ddf77 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476206286.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476311432.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476311432.png new file mode 100644 index 0000000..b698ba8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476311432.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476350602.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476350602.png new file mode 100644 index 0000000..834bf34 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682476350602.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477498176.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477498176.png new file mode 100644 index 0000000..05ab172 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477498176.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477884727.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477884727.png new file mode 100644 index 0000000..668860b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477884727.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477914654.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477914654.png new file mode 100644 index 0000000..7806dea Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682477914654.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682478412527.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682478412527.png new file mode 100644 index 0000000..f794b7f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682478412527.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682478633650.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682478633650.png new file mode 100644 index 0000000..98e0291 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682478633650.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480592506.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480592506.png new file mode 100644 index 0000000..2539308 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480592506.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480716152.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480716152.png new file mode 100644 index 0000000..95c1dfe Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480716152.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480913847.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480913847.png new file mode 100644 index 0000000..4c8615c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682480913847.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682488186891.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682488186891.png new file mode 100644 index 0000000..b92c872 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682488186891.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682494375365.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682494375365.png new file mode 100644 index 0000000..d4451c6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682494375365.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682494494396.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682494494396.png new file mode 100644 index 0000000..ac1731d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682494494396.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682496991032.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682496991032.png new file mode 100644 index 0000000..63eb677 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682496991032.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682497251883.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682497251883.png new file mode 100644 index 0000000..65368cd Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682497251883.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682556566084.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682556566084.png new file mode 100644 index 0000000..eddd30e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682556566084.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682565824241.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682565824241.png new file mode 100644 index 0000000..148d0fe Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682565824241.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682577544086.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682577544086.png new file mode 100644 index 0000000..8462173 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682577544086.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682577630284.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682577630284.png new file mode 100644 index 0000000..85c6217 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682577630284.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682578069348.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682578069348.png new file mode 100644 index 0000000..60329fb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682578069348.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682578584193.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682578584193.png new file mode 100644 index 0000000..47e50ff Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682578584193.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682580097305.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682580097305.png new file mode 100644 index 0000000..9fa67c0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682580097305.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682580126012.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682580126012.png new file mode 100644 index 0000000..ab25830 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1682580126012.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683162129053.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683162129053.png new file mode 100644 index 0000000..cb286e2 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683162129053.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683162653050.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683162653050.png new file mode 100644 index 0000000..ff3d058 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683162653050.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163355943.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163355943.png new file mode 100644 index 0000000..4c5361d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163355943.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163429211.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163429211.png new file mode 100644 index 0000000..129eb64 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163429211.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163732991.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163732991.png new file mode 100644 index 0000000..79cb7bc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163732991.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163807012.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163807012.png new file mode 100644 index 0000000..015d074 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683163807012.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188408798.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188408798.png new file mode 100644 index 0000000..e40a232 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188408798.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188444555.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188444555.png new file mode 100644 index 0000000..74a43cf Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188444555.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188471933.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188471933.png new file mode 100644 index 0000000..12d33de Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683188471933.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683350231551.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683350231551.png new file mode 100644 index 0000000..0874911 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683350231551.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683350275719.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683350275719.png new file mode 100644 index 0000000..3ff90c4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683350275719.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683351095131.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683351095131.png new file mode 100644 index 0000000..54c9b85 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683351095131.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683354561889.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683354561889.png new file mode 100644 index 0000000..cc6c9a5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683354561889.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683354989263.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683354989263.png new file mode 100644 index 0000000..627c773 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683354989263.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683363039636-1690349401673.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683363039636-1690349401673.png new file mode 100644 index 0000000..daa5849 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683363039636-1690349401673.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683363039636.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683363039636.png new file mode 100644 index 0000000..daa5849 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683363039636.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364198087-1690533535579.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364198087-1690533535579.png new file mode 100644 index 0000000..d222439 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364198087-1690533535579.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364198087.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364198087.png new file mode 100644 index 0000000..d222439 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364198087.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364436315-1690533535580.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364436315-1690533535580.png new file mode 100644 index 0000000..ea7770f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364436315-1690533535580.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364436315.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364436315.png new file mode 100644 index 0000000..ea7770f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364436315.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364680503.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364680503.png new file mode 100644 index 0000000..a83c155 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683364680503.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683365066926-1690533535580.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683365066926-1690533535580.png new file mode 100644 index 0000000..df9ca6f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683365066926-1690533535580.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683365066926.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683365066926.png new file mode 100644 index 0000000..df9ca6f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683365066926.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385255826.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385255826.png new file mode 100644 index 0000000..90a269c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385255826.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385333460.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385333460.png new file mode 100644 index 0000000..9eda8e6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385333460.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385335185.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385335185.png new file mode 100644 index 0000000..9eda8e6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385335185.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385500897.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385500897.png new file mode 100644 index 0000000..e71eb9b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385500897.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385608824.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385608824.png new file mode 100644 index 0000000..c8f5f78 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683385608824.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882754527.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882754527.png new file mode 100644 index 0000000..737a0a7 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882754527.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882823511.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882823511.png new file mode 100644 index 0000000..7144bdf Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882823511.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882921502.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882921502.png new file mode 100644 index 0000000..92d4bfe Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683882921502.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883074047.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883074047.png new file mode 100644 index 0000000..23fd060 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883074047.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883090728.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883090728.png new file mode 100644 index 0000000..9f9a8b8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883090728.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883112782.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883112782.png new file mode 100644 index 0000000..d291e7f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883112782.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883374643.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883374643.png new file mode 100644 index 0000000..8a8f5b0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883374643.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883394612.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883394612.png new file mode 100644 index 0000000..ee5d194 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883394612.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883660552.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883660552.png new file mode 100644 index 0000000..735a57f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883660552.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883695289.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883695289.png new file mode 100644 index 0000000..bbbde11 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883695289.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883724768.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883724768.png new file mode 100644 index 0000000..a7d6ec2 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1683883724768.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684157682241.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684157682241.png new file mode 100644 index 0000000..13f69d7 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684157682241.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684158072779.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684158072779.png new file mode 100644 index 0000000..24bf8ac Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684158072779.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684302698248.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684302698248.png new file mode 100644 index 0000000..f8d8619 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684302698248.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684302778377.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684302778377.png new file mode 100644 index 0000000..5755952 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684302778377.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684460441614.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684460441614.png new file mode 100644 index 0000000..2c30a53 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684460441614.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684461046181.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684461046181.png new file mode 100644 index 0000000..413db4f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684461046181.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684461701620.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684461701620.png new file mode 100644 index 0000000..2ecc93d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684461701620.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684463528680.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684463528680.png new file mode 100644 index 0000000..0cb2eb6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684463528680.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684478815640.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684478815640.png new file mode 100644 index 0000000..46808a1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684478815640.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684480894743.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684480894743.png new file mode 100644 index 0000000..c9116db Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684480894743.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487637025.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487637025.png new file mode 100644 index 0000000..4cf375c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487637025.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487715655.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487715655.png new file mode 100644 index 0000000..4944783 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487715655.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487779164.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487779164.png new file mode 100644 index 0000000..1d31418 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487779164.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487839928.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487839928.png new file mode 100644 index 0000000..d78470a Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684487839928.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684488376469.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684488376469.png new file mode 100644 index 0000000..6440c25 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684488376469.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684488405011.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684488405011.png new file mode 100644 index 0000000..31cb569 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684488405011.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684489112904.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684489112904.png new file mode 100644 index 0000000..1441ea9 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684489112904.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684565503347.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684565503347.png new file mode 100644 index 0000000..44a8f3a Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684565503347.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684827427264.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684827427264.png new file mode 100644 index 0000000..04fb8ed Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684827427264.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684890693363.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684890693363.png new file mode 100644 index 0000000..041c744 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684890693363.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684890943094.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684890943094.png new file mode 100644 index 0000000..50a455e Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684890943094.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684891013180.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684891013180.png new file mode 100644 index 0000000..ad94e0f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684891013180.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684891029981.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684891029981.png new file mode 100644 index 0000000..6677be4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684891029981.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684897738491.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684897738491.png new file mode 100644 index 0000000..2e5c2c6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684897738491.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684897782833.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684897782833.png new file mode 100644 index 0000000..7cc9701 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684897782833.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684912274904.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684912274904.png new file mode 100644 index 0000000..dfa357b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1684912274904.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1686885192862.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1686885192862.png new file mode 100644 index 0000000..4591e92 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1686885192862.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687330010547.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687330010547.png new file mode 100644 index 0000000..477930d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687330010547.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687330312538.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687330312538.png new file mode 100644 index 0000000..1039456 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687330312538.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657562841.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657562841.png new file mode 100644 index 0000000..b2a8649 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657562841.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657603246.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657603246.png new file mode 100644 index 0000000..1379377 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657603246.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657661761.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657661761.png new file mode 100644 index 0000000..23b65dc Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687657661761.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687765256680.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687765256680.png new file mode 100644 index 0000000..db04e4f Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687765256680.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687769339457.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687769339457.png new file mode 100644 index 0000000..906678b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1687769339457.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690348134594.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690348134594.png new file mode 100644 index 0000000..1eca256 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690348134594.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690349913931.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690349913931.png new file mode 100644 index 0000000..021a38a Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690349913931.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362496438.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362496438.png new file mode 100644 index 0000000..265dda6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362496438.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362518448.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362518448.png new file mode 100644 index 0000000..036d971 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362518448.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362672386.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362672386.png new file mode 100644 index 0000000..2439f67 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362672386.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362709902.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362709902.png new file mode 100644 index 0000000..f902f7b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362709902.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362787035.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362787035.png new file mode 100644 index 0000000..0f7747b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690362787035.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690363965192.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690363965192.png new file mode 100644 index 0000000..13f4fe3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690363965192.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690507542637.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690507542637.png new file mode 100644 index 0000000..f956572 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690507542637.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690507600043.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690507600043.png new file mode 100644 index 0000000..57a678c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690507600043.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690511433594.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690511433594.png new file mode 100644 index 0000000..9efe2e4 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690511433594.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690516506417.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690516506417.png new file mode 100644 index 0000000..9a30950 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690516506417.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533751478.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533751478.png new file mode 100644 index 0000000..3594ab5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533751478.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533770048.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533770048.png new file mode 100644 index 0000000..da8b7a3 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533770048.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533809917.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533809917.png new file mode 100644 index 0000000..9eaa9f5 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1690533809917.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1695189588009.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1695189588009.png new file mode 100644 index 0000000..1eacdbd Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1695189588009.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1697514669631.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1697514669631.png new file mode 100644 index 0000000..b570fe0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1697514669631.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/1697514693682.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1697514693682.png new file mode 100644 index 0000000..d8ea523 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/1697514693682.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/GIF.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/GIF.gif new file mode 100644 index 0000000..a66fbf8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/GIF.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianji.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianji.gif new file mode 100644 index 0000000..3b1a5a8 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianji.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianjie2.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianjie2.gif new file mode 100644 index 0000000..b0bcf02 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianjie2.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianjiex.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianjiex.gif new file mode 100644 index 0000000..8e0ba04 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/chaolianjiex.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/checkuserName.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/checkuserName.gif new file mode 100644 index 0000000..fbfc863 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/checkuserName.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/fixeddingwei.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/fixeddingwei.gif new file mode 100644 index 0000000..fcb1d88 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/fixeddingwei.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_6ZwJPs9HkC.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_6ZwJPs9HkC.png new file mode 100644 index 0000000..1258a07 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_6ZwJPs9HkC.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_9dCv8raLh-.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_9dCv8raLh-.png new file mode 100644 index 0000000..b559d5c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_9dCv8raLh-.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_IJOzvAeodc.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_IJOzvAeodc.png new file mode 100644 index 0000000..57d8784 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_IJOzvAeodc.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_PHNwnXnsWv.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_PHNwnXnsWv.png new file mode 100644 index 0000000..c865ccf Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_PHNwnXnsWv.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_UDJErYr8iM.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_UDJErYr8iM.png new file mode 100644 index 0000000..d59c4c0 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_UDJErYr8iM.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_XMWA0EjBUI.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_XMWA0EjBUI.png new file mode 100644 index 0000000..258bfeb Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_XMWA0EjBUI.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_bjXPJoLb6a-1690508517199.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_bjXPJoLb6a-1690508517199.png new file mode 100644 index 0000000..7f1fa18 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_bjXPJoLb6a-1690508517199.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_bjXPJoLb6a.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_bjXPJoLb6a.png new file mode 100644 index 0000000..7f1fa18 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_bjXPJoLb6a.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_elceCM4Wbp.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_elceCM4Wbp.png new file mode 100644 index 0000000..0b260ad Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_elceCM4Wbp.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_hZ6yocZGY3.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_hZ6yocZGY3.png new file mode 100644 index 0000000..4aa88a1 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_hZ6yocZGY3.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_j-xo-xB5c8.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_j-xo-xB5c8.png new file mode 100644 index 0000000..97e99e6 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_j-xo-xB5c8.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_kq2Dk1Fggy.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_kq2Dk1Fggy.png new file mode 100644 index 0000000..fc43f71 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_kq2Dk1Fggy.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_lJfO5hjUqL.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_lJfO5hjUqL.png new file mode 100644 index 0000000..46c8a55 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_lJfO5hjUqL.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_rUX4imBP5t.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_rUX4imBP5t.png new file mode 100644 index 0000000..781013b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_rUX4imBP5t.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_rdwmpig76n.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_rdwmpig76n.png new file mode 100644 index 0000000..391a414 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_rdwmpig76n.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_uTNSasJcFd.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_uTNSasJcFd.png new file mode 100644 index 0000000..a2d938d Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/image_uTNSasJcFd.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/img008_sCTelqarx-.png b/语言/Java/大三前/朝花夕拾/尚硅谷/images/img008_sCTelqarx-.png new file mode 100644 index 0000000..f8cd62c Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/img008_sCTelqarx-.png differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/jingxi.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/jingxi.gif new file mode 100644 index 0000000..11388c7 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/jingxi.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/js.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/js.gif new file mode 100644 index 0000000..275ba89 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/js.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/new.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/new.gif new file mode 100644 index 0000000..cde465b Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/new.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/newhtml.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/newhtml.gif new file mode 100644 index 0000000..21eee69 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/newhtml.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/regist.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/regist.gif new file mode 100644 index 0000000..a676d16 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/regist.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/switchex.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/switchex.gif new file mode 100644 index 0000000..e7f3869 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/switchex.gif differ diff --git a/语言/Java/大三前/朝花夕拾/尚硅谷/images/v-on.gif b/语言/Java/大三前/朝花夕拾/尚硅谷/images/v-on.gif new file mode 100644 index 0000000..8cbeb34 Binary files /dev/null and b/语言/Java/大三前/朝花夕拾/尚硅谷/images/v-on.gif differ diff --git a/语言/Java/大三前/朝花夕拾/蓝桥杯/每天一道题蓝桥真题.md b/语言/Java/大三前/朝花夕拾/蓝桥杯/每天一道题蓝桥真题.md new file mode 100644 index 0000000..7dbb7f5 --- /dev/null +++ b/语言/Java/大三前/朝花夕拾/蓝桥杯/每天一道题蓝桥真题.md @@ -0,0 +1,1353 @@ +# D1 第十届蓝桥javaB组 + +## A组队 白给题 + +![image-20250312222608784](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250312222608784.png) + +## B 不同字串 智障题 不多赘述 + +![image-20250312222803442](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250312222803442.png) + +```java +import java.util.HashSet; +import java.util.Set; +// 1:无需package +// 2: 类名必须Main, 不可修改 + +public class Main { + public static void main(String[] args) { + String s = "0100110001010001"; + Set hashSet = new HashSet(); + int n = 1; + while (n <= s.length()) { + for (int i =n; i <=s.length(); i++) { + String str = s.substring(i - n, i); + hashSet.add(str); + } + n++; + } + System.out.println(hashSet.size()); + } +} +``` + +**hashset有去重的功能 ** 集合的知识点 + +# 第十一届蓝桥杯 javaB + +![image-20250324171543621](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250324171543621.png) + +```java +import java.util.Scanner; + +import static java.lang.Math.abs; +// 1:无需package +// 2: 类名必须Main, 不可修改 + +public class Main { + static int dir[][] = {{1,0}, {1, 1}}; + static int[][] f = new int[105][105]; + static int ans = 0; + static int n; + + static void dfs(int x, int y, int sum, int left, int right) { + if (x == n && abs(left - right) <= 1) { + ans = Math.max(ans, sum); + return; + } + for (int i = 0; i < 2; i++) { + int nx = x + dir[i][0]; + int ny = y + dir[i][1]; + if (nx >= 1 && nx <= n && ny >= 1 && ny <= nx) { + if (i == 0) dfs(nx, ny, sum + f[nx][ny], left + 1, right); + else dfs(nx, ny, sum + f[nx][ny], left, right + 1); + } + } + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + // 去掉重复定义 + n = sc.nextInt(); + + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= i; j++) { + f[i][j] = sc.nextInt(); + } + } + // 从 (1, 1) 开始调用 + dfs(1, 1, f[1][1], 0, 0); + System.out.println(ans); + } + +} +``` + +## I 字串分值和 + +![image-20250324172709220](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250324172709220.png) + +```java +利用hashset 来存字串不同的字符 + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Scanner; + +import static java.lang.Math.abs; +// 1:无需package +// 2: 类名必须Main, 不可修改 + +public class Main { + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + String s= sc.nextLine(); + int ans=0; + for(int i=0;i set = new HashSet<>(); + for(int j=i;jset = new HashSet<>(); + for(long i=1;i*i0){ + num+=x/5; + x/=5; + } + return num; + } + final static int N = (int)1e7 ; + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + for(int i=1;i<=N;i++){ + if(f(i)>=n){ + if(f(i)==n){ + System.out.println(i); + }else{ + System.out.println(-1); + } + return; + } + } + } +} + +暴力解题 + ======================= + 利用二分查找 + import java.util.Scanner; + +public class Main { + static long f(long x) { + long num = 0; + while (x > 0) { + num += x / 5; + x /= 5; + } + return num; + } + + final static long N = (long) 9e18; + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + long l = 1, r = N; + while (l < r) { + long mid = (l + r) >> 1; + if(f(mid)>=n)r=mid; + else l=mid+1; + } + if(f(l)==n)System.out.println(l); + else System.out.println(-1); + } +} +``` + +![image-20250328152502778](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250328152502778.png) + +```JAVA +import java.util.Scanner; + + + 去他娘的暴力解决一切 +public class Main { + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + int m = in.nextInt(); + int[][] arr = new int[n + 1][m + 1]; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + arr[i][j] = in.nextInt(); + } + } + int ans = 0; + + int limit = in.nextInt(); + // 遍历所有可能的子矩阵左上角 (i, j) + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + // 遍历所有可能的子矩阵右下角 (a, b) + for (int a = i+1; a <= n; a++) { + for (int b = j+1; b <= m; b++) { + int maxVal = Integer.MIN_VALUE; + int minVal = Integer.MAX_VALUE; + // 计算子矩阵的最大值和最小值 + for (int x = i; x <= a; x++) { + for (int y = j; y <= b; y++) { + maxVal = Math.max(maxVal, arr[x][y]); + minVal = Math.min(minVal, arr[x][y]); + } + } + } + } + } + } + System.out.println(ans); + } +} +``` + + + +## F 最大子矩阵(窗口滑动问题 +双端队列 ) + +![image-20250328152512763](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250328152512763.png) + +``` +窗口滑动问题 +双端队列 + +``` + +## **G 数组切分(线性DP 上升子序列问题?)** + +题目描述 + +已知一个长度为 N 的数组:A1, A2, A3, ...AN 恰好是 1 ∼ N 的一个排列。现在要求你将 A 数组切分成若干个 (最少一个,最多 N 个) 连续的子数组,并且每个子数组中包含的整数恰好可以组成一段连续的自然数。 + +例如对于 A = {1, 3, 2, 4}, 一共有 5 种切分方法: + +{1}{3}{2}{4}:每个单独的数显然是 (长度为 1 的) **一段连续的自然数**。 + +{1}{3, 2}{4}:{3, 2} 包含 2 到 3,是 **一段连续的自然数**,另外 {1} 和 {4} 显然也是。 + +{1}{3, 2, 4}:{3, 2, 4} 包含 2 到 4,是 **一段连续的自然数**,另外 {1} 显然也是。 + +{1, 3, 2}{4}:{1, 3, 2} 包含 1 到 3,是 **一段连续的自然数**,另外 {4} 显然也是。 + +{1, 3, 2, 4}:只有一个子数组,包含 1 到 4,是 **一段连续的自然数**。 + +输入格式 + +第一行包含一个整数 N。第二行包含 N 个整数,代表 A 数组。 + + 输出格式 + +输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值。 + +样例输入 + +``` +4 +1 3 2 4 +``` + +样例输出 + +``` +5 +``` + +提示 + +对于 30% 评测用例,1 ≤ N ≤ 20. + +对于 100% 评测用例,1 ≤ N ≤ 10000. + + + +```java + +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(), mod = (int) (1e9 + 7); + int[] arr = new int[n + 1], f = new int[n + 1]; + for (int i = 1; i <= n; i++) arr[i] = sc.nextInt(); + f[0] = 1; + for (int i = 1; i <= n; i++) { + int max = arr[i], min = arr[i]; + for (int j = i; j > 0; j--) { + max = Math.max(max, arr[j]); + min = Math.min(min, arr[j]); + if (max - min == i - j) f[i] = (f[i] + f[j - 1]) % mod; + /** + * 假定当前处于第 i 个元素,你要考虑把数组从第 j 个元素到第 i 个元素划分成一个子数组(1 ≤ j ≤ i)。要是这个子数组(arr[j], arr[j + 1], ..., arr[i]) + * 里的整数可以构成一段连续的自然数,那么把前 i 个元素进行切分的方法数量,就等于把前 j - 1 个元素进行切分的方法数量。 + * 具体说明如下: + * 若子数组 [j, i] 中的整数能构成一段连续的自然数,那么在计算前 i 个元素的切分方法时,就可以把前 j - 1 个元素的每一种切分方法与子数组 [j, i] 组合起来。 + * 也就是说,前 j - 1 个元素的每一种切分方法,都能够通过添加子数组 [j, i] 得到前 i 个元素的一种切分方法。 + * 而 f[j - 1] 代表的是前 j - 1 个元素的切分方法数量,所以当子数组 [j, i] 满足条件时,就可以把 f[j - 1] 累加到 f[i] 里。 + */ + } + } + System.out.println(f[n]); + } +} +``` + + + + + +# 第十四届蓝桥杯javaB + +## A 阶乘求和(找规律 高进度) + +![image-20250326213201443](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250326213201443.png) + + + + + +## B 幸运数字 (模拟+进制转换) + +![image-20250326210045198](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250326210045198.png) + +```java +import java.util.Scanner; + +public class Main { + + static boolean ten(int x) { + int num=x; + int cnt = 0; + while (x > 0) { + cnt+=x%10; + x/=10; + } + return num%cnt==0; + } + static boolean eight(int x){ + int num=x; + int cnt = 0; + while (x > 0) { + cnt+=x%8; + x/=8; + } + return num%cnt==0; + } + static boolean tow(int x){ + int num=x; + int cnt = 0; + while (x > 0) { + cnt+=x%2; + x/=2; + } + return num%cnt==0; + } + + static boolean sixteen(int x){ + int num=x; + int cnt = 0; + while (x > 0) { + cnt+=x%16; + x/=16; + } + return num%cnt==0; + } + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int sum=0,i=0; + for(i=1;;i++){ + if(ten(i)&&eight(i)&&sixteen(i)&&tow(i)){ + System.out.println(i); + sum++; + } + if(sum==2023){ + break; + } + } + System.out.println(i); + } +} + +很简单的模拟+遍历 +``` + + + + + + + +## **C:** 数组分割(数学+读题) + +【问题描述】 +小蓝有一个长度为 N 的数组 A = [ A 0 , A 1 , . . . , A N − 1 ] 。现在小蓝想要从 A 对应的数组下标所构成的集合 I = { 0 , 1 , 2 , . . . , N − 1 } 中找出一个子集 R 1 ,那么 R 1在 I 中的补集为 R 2 。记 S 1 = ∑ r ∈ R 1 A r , S 2 = ∑ r ∈ R 2 A r,我们要求 S 1 和 S 2 均为 偶数,请问在这种情况下共有多少种不同的 R 1。当 R1 或 R 2 为空集时我们将 S 1 或 S 2 视为 0。 +【输入格式】 +第一行一个整数 T ,表示有 T 组数据。 接下来输入 T 组数据,每组数据包含两行:第一行一个整数 N ,表示数组 A 的长度;第二行输入 N 个整数从左至右依次为 A 0 , A 1 , . . . , A N − 1 ,相邻元素之 间用空格分隔。 +【输出格式】 +对于每组数据,输出一行,包含一个整数表示答案,答案可能会很大,你 +需要将答案对 1000000007 进行取模后输出。 +【样例输入】 +2 +2 +6 6 +2 +1 6 +【样例输出】 +4 +0 + +```java + +import java.math.BigInteger; +import java.util.Scanner; + +public class Main { + static BigInteger mod = new BigInteger("1000000007"); + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int t = sc.nextInt(); + while (t-- > 0) { + int n = sc.nextInt(); + int odd = 0, even = 0; + for (int i = 0; i < n; i++) { + int x = sc.nextInt(); + if (x % 2 == 0) { + even++; + } else { + odd++; + } + } + if (odd % 2 != 0) { + System.out.println(0); + continue; + } + even = even + (odd == 0 ? 0 : odd - 1); + BigInteger ans = new BigInteger("2"); + BigInteger dp = new BigInteger("1"); + + for (long i = 1, j = even; i < even; i++, j--) { // 排列组合无顺序 C + BigInteger u = new BigInteger(String.valueOf(j)); + BigInteger v = new BigInteger(String.valueOf(i)); + dp = dp.multiply(u).divide(v); + ans = ans.add(dp); + } + System.out.println(ans.mod(mod)); + } + } +} +``` + + + + + +## D、矩形总面积(数学) + +![image-20250330200313714](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250330200313714.png) + +```java +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int x1 = sc.nextInt(); + int y1 = sc.nextInt(); + int x2 = sc.nextInt(); + int y2 = sc.nextInt(); + int x3 = sc.nextInt(); + int y3 = sc.nextInt(); + int x4 = sc.nextInt(); + int y4 = sc.nextInt(); + long area1 = (long) (x2 - x1) * (y2 - y1); // 计算第一个矩形的面积 + long area2 = (long) (x4 - x3) * (y4 - y3); // 计算第二个矩形的面积 + long overlapArea=0; + long l = Math.min(x2, x4) - Math.max(x1, x3); + long w= Math.min(y2,y4)-Math.max(y1,y3); + if (l >=0&&w >=0){ + overlapArea= l * w; + } + long Area = area1 + area2 - overlapArea; // 总面积 + System.out.println(Area); // 输出总面积 + } +} +``` + +## E 蜗牛(动态规划) + +这天,一只蜗牛来到了二维坐标系的原点。 + +在 x 轴上长有 n 根竹竿。它们平行于 y 轴,底部纵坐标为 0,横坐标分别为 x1, x2, ..., xn。竹竿的高度均为无限高,宽度可忽略。蜗牛想要从原点走到第 n 个竹竿的底部也就是坐标 (xn, 0)。它只能在 x 轴上或者竹竿上爬行,在 x 轴上爬行速度为 1 单位每秒;由于受到引力影响,蜗牛在竹竿上向上和向下爬行的速度分别为 0.7 单位每秒和 1.3 单位每秒。 + +为了快速到达目的地,它施展了魔法,在第 i 和 i + 1 根竹竿之间建立了传送门(0 < i < n),如果蜗牛位于第 i 根竹竿的高度为 ai 的位置 (xi , ai),就可以瞬间到达第 i + 1 根竹竿的高度为 bi+1 的位置 (xi+1, bi+1),请计算蜗牛最少需要多少秒才能到达目的地。 + +输入格式 + +输入共 1 + n 行,第一行为一个正整数 n; + +第二行为 n 个正整数 x1, x2, . . . , xn; + +后面 n − 1 行,每行两个正整数 ai , bi+1。 + +输出格式 + +输出共一行,一个浮点数表示答案(四舍五入保留两位小数)。 + +样例输入 + +``` +3 +1 10 11 +1 1 +2 1 +``` + +样例输出 + +``` +4.20 +``` + + + +```java + +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int[] arr = new int[n+1]; + for (int i = 1; i <= n; i++) arr[i] = sc.nextInt(); + int []a=new int[n+1]; + int []b=new int[n+1]; + for(int i=1;ia[i])?(b[i-1]-a[i])/1.3: (a[i]-b[i-1])/0.7)); + /** + * ((b[i-1]>a[i]) 前一个相比现在的高还是矮了 + * (a[i]-b[i-1])/0.7) 向上爬 + * (b[i-1]-a[i])/1.3 向下爬 + */ + + } + System.out.printf("%.2f",dp[n][0]); + } +} +``` + + + +## F买二赠一(二分+贪心) + + + +某商场有 N 件商品,其中第 i 件的价格是 Ai。现在该商场正在进行 “买二赠一” 的优惠活动,具体规则是: + +每购买 2 件商品,假设其中较便宜的价格是 P(如果两件商品价格一样,则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P/2的商品,免费获得这一件商品。可以通过反复购买 2 件商品来获得多件免费商品,但是每件商品只能被购买或免费获得一次。 + +小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱? + + + +第一行包含一个整数 N。 + +第二行包含 N 个整数,代表 A1, A2, A3, . . . ,AN。 + + + +输出一个整数,代表答案。 + + + +``` +7 +1 4 2 8 5 7 1 +``` + + + +``` +25 +``` + +```JAVA +import java.util.Arrays; +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n = in.nextInt(); + int[] arr = new int[n]; + for (int i = 0; i < n; i++) + arr[i] = in.nextInt(); + long res = 0; + boolean[] flag = new boolean[n]; + int item = 0; + Arrays.sort(arr); + int k = n - 1; + for (int i = n - 1; i >= 0; i--) { + if (flag[i]) continue; + item++; + if (item == 2) { + int l = 0; + int r = k; + while (l < r) { + int mid = l + r + 1 >> 1; + if (arr[mid] * 2 <= arr[i]) + l = mid; + else r = mid - 1; + } + if (arr[l] * 2 <= arr[i]) { + flag[l] = true;//二分出的点可以报销,标记此点不需要统计答案; + k = r - 1;//二分临界端点左移 + } + item = 0; + } + } + for (int i = 0; i < n; i++) if (!flag[i]) res += arr[i];//统计没有标记的答案,被标记过的都是报销价格的。 + System.out.println(res); + + } +} + + +``` + + + + + +## G合并石子(区间DP变形) + +题目描述 + +在桌面从左至右横向摆放着 N 堆石子。每一堆石子都有着相同的颜色,颜色可能是颜色 0,颜色 1 或者颜色 2 中的其中一种。 + +现在要对石子进行合并,规定每次只能选择位置相邻并且颜色相同的两堆石子进行合并。合并后新堆的相对位置保持不变,新堆的石子数目为所选择的两堆石子数目之和,并且新堆石子的颜色也会发生循环式的变化。具体来说:两堆颜色 0 的石子合并后的石子堆为颜色 1,两堆颜色 1 的石子合并后的石子堆为颜色 2,两堆颜色 2 的石子合并后的石子堆为颜色 0。本次合并的花费为所选择的两堆石子的数目之和。 + +给出 N 堆石子以及他们的初始颜色,请问最少可以将它们合并为多少堆石子?如果有多种答案,选择其中合并总花费最小的一种,合并总花费指的是在所有的合并操作中产生的合并花费的总和。 + +输入格式 + +第一行一个正整数 N 表示石子堆数。 + +第二行包含 N 个用空格分隔的正整数,表示从左至右每一堆石子的数目。 + +第三行包含 N 个值为 0 或 1 或 2 的整数表示每堆石头的颜色。 + +输出格式 + +一行包含两个整数,用空格分隔。其中第一个整数表示合并后数目最少的石头堆数,第二个整数表示对应的最小花费。 + +样例输入 + +``` +5 +5 10 1 8 6 +1 1 0 2 2 +``` + +样例输出 + +``` +2 44 +``` + +```java +import java.util.Scanner; + +public class Main { + static int N = 305; + static int n; + static int INF = (int) 1e9 + 7; + static int a[] = new int[N]; // 前缀和数组(a[i]表示前i堆石子总和) + static int w[][] = new int[N][N]; // w[i][j]表示合并区间[i,j]的最小总花费(无论颜色) + static int c[][] = new int[N][N]; // c[i][j]表示区间[i,j]合并后的最少堆数 + static int f[][][] = new int[N][N][3]; // f[i][j][col]表示将区间[i,j]合并成颜色col的最小花费 + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + n = in.nextInt(); + for (int i = 1; i <= n; i++) { + a[i] = in.nextInt() + a[i - 1]; // 计算前缀和 + } + init(); + for (int i = 1; i <= n; i++) { + int color = in.nextInt(); + f[i][i][color] = 0; // 单堆无需合并,花费为0 + } + + for (int len = 1; len <= n; len++) { + for (int l = 1; l + len - 1 <= n; l++) { + int r = l + len - 1; + for (int color = 0; color <= 2; color++) { + // tmp 表示尝试将区间[l,r]合并成颜色(color+1)%3的最小花费 + int tmp = INF; + for (int k = l; k < r; k++) { + if (f[l][k][color] != INF && f[k + 1][r][color] != INF) { + // 合并后的总花费 = 左区间花费 + 右区间花费 + 合并操作的花费(即总石子数) + tmp = Math.min(tmp, f[l][k][color] + f[k + 1][r][color] + a[r] - a[l - 1]); + } + } + if (tmp != INF) { // 如果存在合法合并方式 + c[l][r] = 1; // 合并后堆数变为1 + // 更新合并后的颜色为(color+1)%3的状态(因为两堆color合并后颜色会循环变化) + f[l][r][(color + 1) % 3] = Math.min(tmp, f[l][r][(color + 1) % 3]); + // 同时更新全局最小花费(无论颜色) + w[l][r] = Math.min(w[l][r], f[l][r][(color + 1) % 3]); + } + } + + // 处理分割点:可能不合并成一堆,而是分割成两个子区间 + // 此时需要更新c[l][r]和w[l][r]的可能更优解 + for (int k = l; k < r; k++) { + // 如果分割后的堆数更少 + if (c[l][r] > c[l][k] + c[k + 1][r]) { + c[l][r] = c[l][k] + c[k + 1][r]; // 更新最少堆数 + w[l][r] = w[l][k] + w[k + 1][r]; // 更新总花费 + } else if (c[l][r] == c[l][k] + c[k + 1][r]) { + // 堆数相同,取花费更小的方案 + w[l][r] = Math.min(w[l][r], w[l][k] + w[k + 1][r]); + } + } + } + } + System.out.println(c[1][n] + " " + w[1][n]); + } + + static void init() { + for (int i = 1; i <= n; i++) { + for (int j = i; j <= n; j++) { + c[i][j] = j - i + 1; // 初始化为未合并时的堆数 + if (i != j) w[i][j] = INF; // 初始化花费为极大值(表示不可合并) + for (int color = 0; color <= 2; color++) + f[i][j][color] = INF; // 初始化所有颜色状态为不可达 + } + } + } +} +``` + +# + + + +# 第十五届蓝桥杯javaB + +## A:报数游戏 (找规律) + +![image-20250406151319473](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250406151319473.png) + +```java +找规律 20的倍数是奇数 24的倍数是偶数 +所以地2024202420242是24的倍数 +``` + +## B:类斐波那契循环数(找规律+读题) + +![image-20250406154355890](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250406154355890.png) + +``` +签到题目 就是把这个数放在数组中 然后按照题目给的要求算就是 如果》了当前的数 就false ==ture +``` + +```java +import java.util.ArrayList; +import java.util.List; + +public class Main { + public static void main(String[] args) { + for (int i = (int) 1e7; i > 0; i--) { + if (ans(i)) { + System.out.println(i); + break; + } + } + } + + public static boolean ans(int n) { + String num= Integer.toString(n); + ArrayList arr=new ArrayList<>(); + int len=num.length(); + for (int i = 0; i < len; i++) { + arr.add(num.charAt(i)-'0'); + } + while(true){ + int sum=0; + for (int i = arr.size()-len; i < arr.size(); i++) { + sum+=arr.get(i); + } + arr.add(sum); + if(sum>n){return false;} + if(sum==n){return true;} + } + } +} + +``` + +题目 3227: + +## C:分布式队列 + +时间限制: 2s 内存限制: 512MB 提交: 2229 解决: 523 + +题目描述 + +小蓝最近学习了一种神奇的队列:分布式队列。简单来说,分布式队列包含 N 个节点(编号为 0 至 N − 1,其中 0 号为主节点),其中只有一个主节点,其余为副节点。主/副节点中都各自维护着一个队列,当往分布式队列中添加元素时都是由主节点完成的(每次都会添加元素到队列尾部);副节点只负责同步主节点中的队列。可以认为主/副节点中的队列是一个长度无限的一维数组,下标为 0, 1, 2, 3 . . . ,同时副节点中的元素的同步顺序和主节点中的元素添加顺序保持一致。 + +由于副本的同步速度各异,因此为了保障数据的一致性,元素添加到主节点后,需要同步到所有的副节点后,才具有可见性。 + +给出一个分布式队列的运行状态,所有的操作都按输入顺序执行。你需要回答在某个时刻,队列中有多少个元素具有可见性。 + +输入格式 + +第一行包含一个整数 N,表示节点个数。接下来包含多行输入,每一行包含一个操作,操作类型共有以下三种:add、sync 和 query,各自的输入格式如下: + +1. add element:表示这是一个添加操作,将元素 element 添加到队列中; +2. sync follower_id:表示这是一个同步操作,follower_id 号副节点会从主节点中同步下一个自己缺失的元素; +3. query:查询操作,询问当前分布式队列中有多少个元素具有可见性。 + +输出格式 + +对于每一个 query 操作,输出一行,包含一个整数表示答案。 + +样例输入 + +复制 + +``` +3 +add 1 +add 2 +query +add 1 +sync 1 +sync 1 +sync 2 +query +sync 1 +query +sync 2 +sync 2 +sync 1 +query +``` + +```java +这个题就是看你呢更不能读懂题目的含义了 +该题目也属于基础题目,采用模拟的形式,这个题有一个小技巧在于查询操作只显示元素同步个数,所以添加add操作时,只需要在每次add时count+1,而不需要注意具体添加的是什么值。还有一个注意点是他的测试用例,1≤N≤10,所以直接定义大小为10的数组存储数量即可 + +package moni15; + + +//1:无需package +//2: 类名必须Main, 不可修改 + +//分布式队列 +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + int n = scanner.nextInt(); + int[] count = new int[n]; + while(scanner.hasNext()) { + String str = scanner.next(); + if(str.equals("add")) { + count[0]++; + continue; + } + if(str.equals("sync")) { + int num = scanner.nextInt(); + //同步操作时,被同步的节点数量必须小于主节点 + if(count[0] > count[num])count[num]++; + continue; + } + if(str.equals("query")) { + int m = Integer.MAX_VALUE; + for(int i = 0; i < n;i++) { + //可见数量即最小的元素 + m = Math.min(m,count[i]); + } + System.out.println(m); + } + } + scanner.close(); + } +} +``` + +## D:最优分组 (贪心) + +S 学校里一共有 a2 个两人寝、a3 个三人寝,a4个四人寝,而食堂里有 b4个四人桌和 b6 +个六人桌。学校想要安排学生们在食堂用餐,并且满足每个寝室里的同学都在同一桌就坐,请问这个食堂最多同时满足多少同学用餐? 输入格式 + +采用多组数据输入。 + +输入共 q+1 行。 + +第一行为一个正整数 qq 表示数据组数。 + +后面 qq 行,每行五个非负整数 a2,a3,a4,b4,b6 表示一组数据。 输出格式 + +输出共 qq 行,每行一个整数表示对应输入数据的答案。 样例输入 + +2 3 0 1 0 + +样例输出 + +6 + +```java +优先坐满6人桌,再坐满4人桌。 +先考虑配满情况 3+3 ,4 + 2, 2 + 2 + 2, 4,2+2 +**再考虑不满配的情况 3 + 2 ,4装6,3装4 2装6 2装4 +package moni15; + +import java.util.Scanner; + +//食堂 +//贪心加暴力 +public class Main4 { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + //在此输入您的代码... + int q = scanner.nextInt(); + for(int i = 0;i < q;i++) { + int total = 0; + int a2 = scanner.nextInt(); + int a3 = scanner.nextInt(); + int a4 = scanner.nextInt(); + + int b4 = scanner.nextInt(); + int b6 = scanner.nextInt(); + //先考虑能配对情况 + //先考虑六人桌 + //再考虑四人桌 + + //3+3 + while(a3 >= 2 && b6 >= 1) { + a3 = a3 - 2; + b6--; + total = total + 6; + } + //4+2 + while(a4 >= 1 && a2 >= 1 && b6 >= 1) { + a4--; + a2--; + b6--; + total = total + 6; + } + //1个4 + while(a4 >= 1 && b4 >= 1) { + a4--; + b4--; + total = total + 4; + } + //3个2 + while(a2 >= 3 && b6 >= 1) { + a2 = a2 - 3; + b6--; + total = total + 6; + } + //2个2 + while(a2 >= 2 && b4 >= 1) { + a2 = a2 - 2; + b4--; + total = total + 4; + } + + //匹配不配对的情况 + //1个3 一个2 + while(a3 >= 1 && a2 >= 1 && b6 >= 1) { + a3--; + a2--; + b6--; + total = total + 5; + } + //一个4 + while(a4 >= 1 && b6 >= 1) { + a4--; + b6--; + total = total + 4; + } + //一个3 + while(a3 >= 1 && b4 >= 1) { + a3--; + b4--; + total = total + 3; + } + //一个3 + while(a3 >= 1 && b6 >= 1) { + a3--; + b6--; + total = total + 3; + } + //一个2 + while(a2 >= 1 && b6 >= 1) { + a2--; + b6--; + total = total + 2; + } + //一个2 + while(a2 >= 1 && b4 >= 1) { + a2--; + b4--; + total = total + 2; + } + System.out.println(total); + } + scanner.close(); + } +} + +``` + + + +## E:最优分组(数学期望问题) + +小蓝开了一家宠物店,最近有一种 X 病毒在动物之间进行传染,小蓝为了以防万一打算购买测试剂对自己的宠物进行病毒感染测试。为了减少使用的测试剂数目,小蓝想到了一个好方法:将 N 个宠物平均分为若干组,使得每组恰好有 K 只宠物,这样对同一组的宠物进行采样并混合后用一个试剂进行检测,如果测试结果为阴性则说明组内宠物都未感染 X 病毒;如果是阳性的话则需要对组内所有 K 只宠物单独检测,需要再消耗 K 支测试剂(当 K = 1 时,就没必要再次进行单独检测了,因为组内只有一只宠物,一次检测便能确认答案)。 + +现在我们已知小蓝的宠物被感染的概率为 p,请问 K 应该取值为多少才能使得期望的测试剂的消耗数目最少?如果有多个答案输出最小的 K。 + +输入格式 + +第一行,一个整数 N。 + +第二行,一个浮点数 p。 + +输出格式 + +输出一行,一个整数 K 表示答案。 + +样例输入 + +``` +1000 +0.05 +``` + +样例输出 + +``` +5 +``` + +```java + +就是数学期望问题 至少一个狗 感染是P E(X)=1*K+(1-(1-P)^K)*K +所以说 要用的试剂的期望就是 (1-(1-p)^k)*k*(n/k)+n/k + 然后比大小就可以了 + import java.util.*; + +public class Main { + public static void main(String[] args) { + Scanner in=new Scanner(System.in); + double a=in.nextInt(); + double p=in.nextDouble(); + int best=0; + double min=Double.MAX_VALUE; + for(int i=1;i<=a;i++){ + if(a%i==0){ + double res=(1-Math.pow((1-p),i)*i*a/i+a/i); + if(resset=new HashSet<>(); + Arrays.sort(a); + Mapmap=new HashMap<>(); + for(int i=0;i0){ + cnt+=n%7; + n/=7; + } + System.out.println(cnt); + } +} +``` + +## 常识题 + +**本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。** + +小蓝的IP地址为 `192.168.*.21`,其中 `*` 是一个数字,请问这个数字最大可能是多少? + + + +## 高精度 + +### 题目描述 + +计算 A×B*A*×*B* 。 + +### 输入描述 + +每一行将包含两个整数 A*A* 和 B*B*。备注:每个整数的长度不能超过 1000010000。 + +### 输出描述 + +输出 A×B*A*×*B* 。 + +### 输入输出样例 + +#### 示例 1 + +### 题目描述 + +计算 A×B*A*×*B* 。 + +### 输入描述 + +每一行将包含两个整数 A*A* 和 B*B*。备注:每个整数的长度不能超过 1000010000。 + +### 输出描述 + +输出 A×B + + + +```txt +1000 +2 +``` + + + +```txt +2000 +``` + + + +```java +import java.util.Scanner; +// 1:无需package +// 2: 类名必须Main, 不可修改 +import java.math.BigInteger;***注意导包 +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + while(scan.hasNext()) { + BigInteger a=scan.nextBigInteger(); + BigInteger b=scan.nextBigInteger(); + System.out.println(a.multiply(b)); + } +} +} +``` + +============================================================================================================================================================================================================================================================================================================================ + +## 双指针 + + + +1372 + +```java +package LQ_10; +import java.util.*; + +public class LQ1372 { + public static void main(String [] args) + { + + Scanner scan = new Scanner(System.in); + int n=scan.nextInt();//n个数 + int s=scan.nextInt();//s 目标常数 + int ans=Integer.MAX_VALUE;//表示长度 + int sum=0;//表示和 + int [] arr=new int[n]; + for(int i=0;i=s 那么就是sum=-arr[j] j++这样 i在前面扩大长度 j在后面缩小长度 当i=0){ + System.out.println(a); + } + else{ + System.out.println(-a); + } + } +} + +``` + +## 排序 + +### 冒泡 + +把最大的冒泡到前面去 + +```java +int []arr= {5,8,4,4,6,7,4,8}; +for (int i = arr.length - 1; i > 0; i--) { + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + for (int j = 0; j < i; j++) { + if (arr[j] > arr[j + 1]) { + // 交换 arr[j] 与 arr[j + 1] + int tmp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = tmp; + } + } + } + for(int i:arr) { + System.out.printf(i+" "); + } + 时间复杂度O N^2 +``` + +### 选择 + +选择最小的与前面的交换 + +```java + int []arr= {3,8,4,4,6,7,4,8,9,1,1,1,5,2,7,8,15}; + for(int i=0;i0&&nums[j]>base) { + nums[j+1]=nums[j]; + j--; + } + nums[j+1]=base; + } + + for(int i:nums) { + System.out.printf(i+" "); + } +} +} +``` + +### 快排 + +```java +package LQ_10; + +public class EXE { + public static void main(String[] args) { + int[] nums = { 3, 8, 4, 4, 6, 7, 4, 8, 9, 1, 1, 1, 5, 2, 7, 8, 15 }; + quickSort(nums,0,nums.length-1); + for (int i : nums) { + System.out.printf(i + " "); + } + } + + public static void swap(int[] nums, int i, int j) { + int t = nums[i]; + nums[i] = nums[j]; + nums[j] = t; + } + public static void quickSort(int []nums,int left,int right) { + if(left>right)return;//左边的数等于右边的数 就是说只有一个数了 那还排什么 + int pivot=partition(nums,left,right);//找中枢点 + quickSort(nums,left,pivot-1); + quickSort(nums,pivot+1,right); + } + public static int partition(int []nums,int left,int right) { + int i=left,j=right; + while(i=nums[left])j--; + while(i0) + { + str1.append(a%x); + a/=x; + } + return str1.reverse().toString(); + } +``` + +## 贪心 + +```java +package LQ_10; + +import java.util.*; + +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int n=scan.nextInt(); + List lt=new ArrayList(); + for(int i=0;i1) { + int a=lt.get(0); + int b=lt.get(1); + sum+=a+b; + lt.remove(0); + lt.remove(0); + lt.add(a+b); + Collections.sort(lt); + } + System.out.print(sum); + scan.close(); + } +} +``` + +![image-20241030223825354](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20241030223825354.png) + + + +# 系统学习 + +## 循环 + +### 进制转换 + +```java + +import java.util.Scanner; +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int a=scan.nextInt(); + int out=0; + int pow=1; + while(a>0){ + int c=a%10; + a/=10; + out+=c*pow; + pow*=9; + } + System.out.println(out); + scan.close(); + } +} +``` + +### 枚举法求最大公约数 + +```java +设a, b是两个整数,如果d能整除a且d能整除b,那么,d就称为是a和b的公约数。a和b的公约数中最大的整数称为a和b的最大公约数。 +输入两个正整数a和b,求它们的最大公约数。 +import java.util.Scanner; +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int a = scan.nextInt(), b = scan.nextInt(); + int min= Math.min(a, b); + for(int i=min;i>=1;i--){ + if(a%i==0 && b%i==0){ + System.out.println(i); + break; + } + } + scan.close(); + } +} + + 递归大法 +import java.util.Scanner; +// 1:无需package +// 2: 类名必须Main, 不可修改 + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int a = sc.nextInt(); + int b = sc.nextInt(); + sc.close(); + System.out.println(gcd(a,b)); + } + public static int gcd(int a,int b) { + return b == 0 ? a : gcd(b,a%b); + } +} +``` + +## 数组与字符串 + +### 冒泡排序 + +```java + +import java.util.Scanner; +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int n=scan.nextInt(); + int arr[]=new int[n]; + for(int i=0;iarr[j+1]){ + int temp=arr[j]; + arr[j]=arr[j+1]; + arr[j+1]=temp; + } + } + } + for(int i=0;i= x)//如果被定义为信赖的为1 + arr[i]=1; + else + arr[i]=0; + brr[i]=brr[i-1]+arr[i];//前缀和 + } + for(int i=1;i<=q;i++){ + int l= in.nextInt(),r= in.nextInt(); + System.out.println(brr[r]-brr[l-1]); + } + in.close(); + } + +} +``` + +### 二维差分数 + +给定一个 大小的矩阵 。 +给定 组查询,每次查询为给定 4 个正整数 ,你需要输出 的值。 + +第一行输入 3 个正整数 。 +接下来 行每行输入 个整数,表示 。 +接下来 行,每行输入 4 个正整数 + +对于每次查询,输出一个整数,表示查询的子矩阵的和。 + +```plaintext +3 4 3 +1 7 2 4 +3 6 2 8 +2 1 2 3 +1 1 2 2 +2 1 3 4 +1 3 3 4 +``` + +#### 样例输出 + +```plaintext +17 +27 +21 +``` + +```java +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int n = scan.nextInt(); + int m = scan.nextInt(); + int q = scan.nextInt(); + int[][] sum = new int[n + 1][m + 1]; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + scan.nextInt(); + } + } + + while (q-- > 0) { + int x1 = scan.nextInt(); + int y1 = scan.nextInt(); + int x2 = scan.nextInt(); + int y2 = scan.nextInt(); + int result = sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1]; + System.out.println(result); + } + + scan.close(); + } +} +``` + +## 单调队列 + +### 滑动窗口问题 + +```java +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int[] num = new int[10]; + int n, k; + n = sc.nextInt(); + k = sc.nextInt(); + int[] ans = new int[n - k + 1]; + Deque q = new ArrayDeque(); + for (int i = 0; i < n; i++) { + while (!q.isEmpty() && num[i] > num[q.peekLast()]) { + q.pollLast(); + } + q.addLast(i); + if (i - q.getFirst() >= k) {//如果队列头部的元素已经不在滑动窗口内,则将其移除 + q.pollFirst(); + } + if (i >= k - 1) + ans[i - k + 1] = num[q.getFirst()];//记录当前滑动窗口的最大值 + } + } +} +``` + + + +## 位运算 + +### 相或为k(2星) + +#### 问题描述 + +给定你n个非负整数a[i],你是否可以从中选出一些数进行或运算使得值为k,若可以,则输出Yes,若不可以,则输出No。 + +或运算:二进制位1|1 = 1, 1|0 = 1, 0|0 = 0。 + +#### 输入格式 + +第一行一个t代表数据组数。 + +每组数组第一行二个整数n, k。 + +每组数据第二行n个数a[i]。 + +#### 输出格式 + +输出t行,为符合题目要求的Yes或No。 + +#### 样例输入 + +#### 1 +4 6 +1 2 3 4 + +#### 样例输出 + +Yes + +```java +import java.util.Scanner; +// 1:无需package +// 2: 类名必须Main, 不可修改 +public class Main { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int t = sc.nextInt(); + while(t-->0) { + int n = sc.nextInt(); + int k= sc.nextInt(); + int ans=0; + for(int i=0;i 0) { + //求出能有几个会被5整除的 因为在阶乘中5有1个5 25有2个5 所以说通过循环 来判断这个数究竟能被几个5整除 + num += x / 5; + + x /= 5; + } + return num; + } + + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + long n = scan.nextLong(); + long left = 0L; + long right = (long) 1e18 ; + + while (left < right) { + long mid = (left + right) / 2; + + if(n<=cale(mid)){ + right = mid ; + } + else{ + left = mid+1 ; + } + } + + if(cale(right)!=n){ + System.out.println(-1); + } + else{ + System.out.println(right); + } + scan.close(); + } +} +``` + +## 莫名其妙中间省略了好多 + +## 背包01dp + +```java + n = in.nextInt(); + m = in.nextInt(); + int []v=new int[n+1];//价值 + int []w=new int[n+1];//体积 + for(int i=0;i=w[i]){ + dp[i][j]=Math.max(dp[i][j],dp[i-1][j-w[i]]+v[i]); + } + } + //////////////////////////////// //////////////////////////////////////////////////////////////// + 一维优化 +public class Main { + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n, m; + n = in.nextInt(); + m = in.nextInt(); + int[] v = new int[n + 1]; + int[] w = new int[n + 1]; + for (int i = 0; i < n; i++) { + v[i] = in.nextInt(); + w[i] = in.nextInt(); + } + int[] dp = new int[m + 1]; + for (int i = 0; i < n; i++) { + for (int j = m; j >= w[i]; j--) {//这是从后往前来的 只能这样 因为只有这样 不然从前往后的话就会多加 + dp[j] = Math.max(dp[j], dp[ j - w[i] ] + v[i]); + /* + 是这样的 因为啊 这个dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]); + 需要等价于 + dp[i][j]=dp[i-1][j]; + if(j>=w[i]){ + dp[i][j]=Math.max(dp[i][j],dp[i-1][j-w[i]]+v[i]); + dp[j] = Math.max(dp[j] 是没有错的Math.max(dp[j] 是上一个的 其实就是等价于dp[i][j]=Math.max(dp[i][j] + 可以这么认为 因为此时左边的dp[j]还没有被算出来 而右边的dp[j]是上一个dp[i-1][j]的 已经被算出来的 + */ + + } + } + in.close(); + } +} + +``` + +## 完全背包 + +```java + n = in.nextInt(); + m = in.nextInt(); + int []v=new int[n+1];//价值 + int []w=new int[n+1];//体积 + for(int i=0;i=w[i]){ + dp[i][j]=Math.max(dp[i][j],dp[i][j-w[i]]+v[i]); + } + } + //注意这个 dp[i][j]=Math.max(dp[i][j],dp[i][j-w[i]]+v[i]); + + 其实完全背包和01背包差不多 都是依赖上一层的来推出下一层 + 只不过完全背包可以对同一个物品多次拿去 所以它的上一层就可能是自己发展过来的 所以就是dp[i][j-w[i]]+v[i] + + //////////////////////////////////////////////////////////////////////////////////////////////// + + 一维优化 +public class Main { + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n, m; + n = in.nextInt(); + m = in.nextInt(); + int[] v = new int[n + 1]; + int[] w = new int[n + 1]; + for (int i = 0; i < n; i++) { + v[i] = in.nextInt(); + w[i] = in.nextInt(); + } + int[] dp = new int[m + 1]; + for (int i = 0; i < n; i++) { + for (int j =w[i]; j<=m; j++) {//这是从前往后来的 所以说就是可以直接从w[i]到m 跟上面的反着记就好了 + dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]); + } + } + in.close(); + } +} +``` + +## 多重背包 + +```java +import java.util.Scanner; +// 1:无需package +// 2: 类名必须Main, 不可修改 + +public class Main { + public static void main(String[] args) { + Scanner sc=new Scanner(System.in); + int n=sc.nextInt(),m=sc.nextInt(); + int v[]=new int[n+1]; + int w[]=new int[n+1]; + int c[]=new int[n+1]; + int dp[]=new int[m+1]; + + for (int i = 1; i <= n; i++) { + v[i]=sc.nextInt(); + w[i]=sc.nextInt(); + c[i]= sc.nextInt(); + } + for (int i = 1; i <= n; i++) { + for (int j = m; j >=v[i]; j--) { + for (int k = 0; k*v[i]<=j&&k<=c[i] ; k++) {//不仅选的次数要关注容量 也要关注本身的限制 + dp[j]=Math.max(dp[j],dp[j-k*v[i]]+k*w[i]); + } + } + } + System.out.println(dp[m]); + } +} +O(N*M*K)比较大 只能支持100的数值 + +``` + +## 区间DP + +```JAVA + +题目描述 +在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。例如:输入{1,2,3,4,5},输出33。【3+6+9+15=33】 +输入 +本题应该处理到文件尾,每组输入包括两行,第一行为石子堆的个数n,第二行则为每堆石子的个数。 +输出 +输出最小花费。 +样例输入 +5 +1 2 3 4 5 +样例输出 +33 +import java.util.Scanner; + +// 1:无需package +// 2: 类名必须Main, 不可修改 +public class Main { + static int N = 300; + static int[] s = new int[N];//前缀和 + static int[][] dp = new int[N][N];//i j 这个数组的每一位ij 都代表的是i->j 的最少的花费 + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + int n=in.nextInt(); + for(int i=1;i<=n;i++){ + s[i]=in.nextInt()+s[i-1]; + } + for(int len=2;len<=n;len++){ + for(int l=1;len+l-1<=n;l++){ + int r =len+l-1; + dp[l][r]=Integer.MAX_VALUE; + for(int k = l; k< r; k++){ + dp[l][r]=Math.min(dp[l][r],dp[l][k]+dp[k+1][r]+s[r]-s[l-1]); + } + } + } + System.out.println(dp[1][n]); + } +} +``` + diff --git a/语言/Java/大三前/朝花夕拾/蓝桥杯/蓝桥冲刺.md b/语言/Java/大三前/朝花夕拾/蓝桥杯/蓝桥冲刺.md new file mode 100644 index 0000000..1c6506b --- /dev/null +++ b/语言/Java/大三前/朝花夕拾/蓝桥杯/蓝桥冲刺.md @@ -0,0 +1,137 @@ +# D1 + +![image-20250324223257143](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250324223257143.png) + +```JAVA +import java.util.Scanner; +zheshi +public class Main { + + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int n = scan.nextInt(); + int [][]arr=new int [n+1][n+1]; + int max=0; + for(int i=1;i<=n;i++){ + for(int j=1;j<=i;j++){ + arr[i][j]=scan.nextInt(); + arr[i][j]=Math.max(arr[i][j]+arr[i-1][j],arr[i][j]+arr[i-1][j-1]); + max=Math.max(max,arr[i][j]); + } + } + System.out.println(max); + } + +} +``` + +![image-20250324223214500](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250324223214500.png) + +```JAVA + import java.util.Arrays; + import java.util.Scanner; + + public class Main { + static int n; + static int[] arr = new int[10005]; + static int[] dp = new int[10005]; + static int D(int x) { + if (x == 1) return 1; + else { + for (int i = 2; i * i <= x; i++) { + if (x % i == 0) return i; + } + } + return x; + } + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + n = scan.nextInt(); + for (int i = 1; i <= n; i++) arr[i] = scan.nextInt(); + Arrays.fill(dp,Integer.MIN_VALUE); + dp[1]=arr[1]; + for (int i = 1; i <= n; i++) { + int len=D(n-i); + for(int j=1;j<=len;j++){ + dp[j+i]=Math.max(dp[j+i],dp[i]+arr[i+j]); + } + } + System.out.println(dp[n]); + } + + } +``` + + + +![image-20250324223201421](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250324223201421.png) + +```JAVA +import java.util.Arrays; +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int t = scan.nextInt(); + while (t-- > 0) { + int n, a, b, k; + n = scan.nextInt(); + a = scan.nextInt(); + b = scan.nextInt(); + k = scan.nextInt(); + int[] arr = new int[n + 1]; + int[][] dp = new int[n + 1][n + 1]; + for (int i = 1; i <= n; i++) arr[i] = scan.nextInt(); + for (int v[] : dp) Arrays.fill(v, Integer.MIN_VALUE); + int ans = 0; + dp[0][0] = 0; + for (int i = 1; i <= k; i++) {//k次数 + for (int j = 1; j <= n; j++) {//区间 + for (int x = a; x <= b; x++) {//每次能跳的范围 + if (j >= x) dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - x] + arr[j]); + //关键就在于 J>=X J表示的是 以后的位置 而x表示的是跳的步数 如果j>=x 那就说明 j-x的位置是可达的 + //并且这个题目的解法是从后往前推的 因此就不会由产生后继性 所以我们不用考虑后面的了 红红火火恍恍惚惚哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 + } + ans = Math.max(ans, dp[i][j]); + } + } + System.out.println(ans); + + } + } +} +``` + +# D2 前缀和&&差分 + +![image-20250325190257802](C:\Users\33882\AppData\Roaming\Typora\typora-user-images\image-20250325190257802.png) + +```java +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + int n= scan.nextInt(); + int m=scan.nextInt(); + int []a=new int [n+1]; + for(int i=1;i<=n;i++){ + a[i]=scan.nextInt(); + a[i]=a[i]+a[i-1]; + } + for(int i=0;i docker run 的详细命令 + +docker run -p 80:81 就是访问80 + +端口的时候 就会映射到docker的81端口 + +> docker exec 进入 + + + + + + + +docker commit 提交 + +docker save 保存 + +docker load 加载 + diff --git a/面试/东软.md b/面试/东软.md new file mode 100644 index 0000000..9485884 --- /dev/null +++ b/面试/东软.md @@ -0,0 +1,19 @@ +Collectuons集合 +Java stream lanbada表达式的应用 +error exception +项目里面的全局异常处理 +spring注解 +controller restcontroller +事务失效 +事务的传播级别 +你用过什么数据库 +什么字段添加索引 +内链接和外链接 +sql注入 +前端的知识 +linux常用的命令 +一个文件把文件传送到另一台服务器的命令 +文本文件 内容清空 然后文件保存 + + + diff --git a/面试/八股文/Spring.md b/面试/八股文/Spring.md new file mode 100644 index 0000000..9ad237c --- /dev/null +++ b/面试/八股文/Spring.md @@ -0,0 +1,919 @@ +## 什么是循环依赖 + +多个Bean 相互注入 相互依赖 那么就到底先加载谁??? 就卡住了 报错了 + +## 如何解决循环依赖 + +关键**`提前暴露还未创建完成的Bean`** + + 方法:**三级缓存** + +1. 一级缓存 + - 用于存储**完全初始化**的完整单例化的Bean +2. 二级缓存 + - **尚未*完全初始化*** 但是**已经实例化**的Bean ,用于**提前暴露对象**,**避免循环依赖问题** +3. 三级缓存 + - 用于存储对象工厂 当需要时 可以通过工厂创建早期的Bean(特别是为了支持AOP代理对象的创建) + + + +解决步骤: + +- Spring先**创建Bean的实例** 将其***加入三级缓存***中 +- 当一个Bean需要依赖另一个未初始化的Bean的时候 Spring会从**三级缓存中获取Bean工厂**,并**生成该对象** +- 代理对象**存入二级缓存**,解决依赖 +- 一旦所有依赖Bean被完**全初始化**,Bean将**转移到一级缓存**中 + + + +### 扩展 + +### 只有是依赖的**Bean是单例** + +什么是单例模式 就是一个Bean他只能有一个实例化 + +那么因此Bean1需要2的时候 就创建B B创建的时候需要A 那么正好 + +但是如果是原型模式的话 那么A需要B B需要A的时候就会创建A2 但是A2也需要B 因此就会创建B2 .....循环往复 周而复始 + + + +image-20251024154932330 + +### 并且 必须`不全是`构造器注入 && beanName字母序在前的不能是构造器注入 + +背景:Spring 创建Bean分为三部 + +1. 实例化 --》createBeanInstance 就是new了一个对象 +2. 属性注入 --》populateBean 就是set一些属性 +3. 初始化 --》 initializeBean 执行一些aware接口中的方法 initMethod AOP代理 + + + +所以 当我们全部都使用构造器注入的时候 newA(B b) 就回去执行 new B(A a) 但是tmdA没有构造完啊 那他妈怎么办 + +还能怎么办 换一种思路 那就是set注入 + +image-20251024160334418 + +### 那么我们再次回到创建Bean的三级缓存中 重新回顾一下 + +1. 首先获取单例的Bean 的时候会通过BeanName去找一级缓存 查找完整的Bean 如果找到就返回 找不到就去2 +2. 看看对应的Bean是否在创建中,如果不在直接返回找不到NULL 如果找到 则去二级缓存中找BEAN 找到就返回 没有就3 +3. 去三级缓存中 通过BeanName找到对应的工厂 如果有工厂则创建Bean 且放到earlySingletonObjects中 +4. 三级缓存都没有找到 那么就返回null + + + +我们发现在2中如果Bean没有创建 则是返回null 那么返回了null 以后呢??就是去创建这个Bean了 就调用 createBean 创建Bean 调用的方法就是docreateBean 那么这个docreateBean 是干什么的呢 就是`` 实例化 初始化 属性注入`` + + + +### 在实例化了一个Bean以后 + +就会在**addSingletonFactory**中塞入一个工厂 然后这个工厂调用一个方法addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 我们就可以得到这个Bean + +要注意,此时 Spring 是不知道会不会有循环依赖发生的,但是它不管,反正往 singletonFactories 塞这个工厂,这里就是`提前暴露`。 重点就是在对象实例化之后,都会在三级缓存里加入一个工厂,提前对外暴露还未完整的 Bean,这样如果被循环依赖了,对方就可以利用这个工厂得到一个不完整的 Bean,破坏了循环的条件。 + +### Tip: + +![image-20251024161935634](F:\记录\八股文\image-20251024161935634.png) + + + + + +### Spring 二级缓存行不行 不要三级了 + +先说原因:AOP代理和Bean早期的引用问题 + +如果只是解决循环依赖 那么很简单 二级就可以 但是在AOP的时候 直接使用二级而不做任何处理 会导致我们拿到的Bean 是 **未代理的原始对象** 如果二级都存的是这个 就违反了Bean的生命周期 + +破化了**Bean 初始化流程中 “代理对象生成” 与 “依赖注入” 的衔接环节** + +**若 Bean 需要 AOP 代理,最终暴露给容器和其他依赖 Bean 的必须是 “代理对象”,而非原始对象** + +## Bean的生命周期 + +`实例化` --》 `属性注入`--》 初始化前的扩展机制--》 初始化前--》 `初始化`--》 初始化后--》 `使用`--》`销毁` + +实例化: SPring容器 根据配置文件或注解实例化Bean对象 + +属性注入: Spring将依赖(setter/字段注入) 注入到 Bean实例中 + +初始化前的扩展机制: if(Bean对象实现了BeanNameAware... aware接口)则执行aware注入 + +初始化前: 可以通过BeanPostProcessor接口对Bean进行一些额外的处理 比如可以获取Bean的名字 工厂 ApplicationContext等容器资源 + +初始化: - `InitializingBean` 接口提供了一个 `afterPropertiesSet` 方法,用于在 Bean 的所有属性设置完成后执行一些自定义初始化逻辑。开发者也可以通过 `@PostConstruct` 注解或者 XML/Java 配置中的 `init-method` 属性,来指定初始化方法。 + +初始化后: + +使用Bean: + +销毁:调用DisposiableBean 接口提供了destory方法 + +image-20251024164026531 + +## SPring 核心特性 + +Spring框架核心特性包括: + +- **IoC容器**:Spring通过控制反转实现了对象的创建和对象间的依赖关系管理。开发者只需要定义好Bean及其依赖关系,Spring容器负责创建和组装这些对象。 +- **AOP**:面向切面编程,允许开发者定义横切关注点,例如事务管理、安全控制等,独立于业务逻辑的代码。通过AOP,可以将这些关注点模块化,提高代码的可维护性和可重用性。 +- **事务管理**:Spring提供了一致的事务管理接口,支持声明式和编程式事务。开发者可以轻松地进行事务管理,而无需关心具体的事务API。 +- **MVC框架**:Spring MVC是一个基于Servlet API构建的Web框架,采用了模型-视图-控制器(MVC)架构。它支持灵活的URL到页面控制器的映射,以及多种视图技术。 + +但是也可以这么分 + +`核心容器` + +- SpringCore 包含了`DI 依赖注入 & Ioc 控制反转` +- SpringBean 管理Bean的定义和生命周期 +- SpringContext 基于Core 和Bean的高级容器 +- SpringExpressionLanguage 表达式语言 + +`Aop(切面编程)` + +- SPringAop + +`数据访问` + +- SPringJDBC +- SpringORM :(mybatis就是这个管着) +- SpringTransaction` 事务管理` + +`Web层` + +- SpringWeb 提供基础的Web开发支持 +- SpringMVC 实现了MCV model-controller-view 用于构建Http请求的Web应用 +- SpringWebFlux + + + +## Spring 的核心特征 + +DI IOC AOP + +image-20251024183530002 + +## 什么是SPring Ioc + +**def**:Inversion of Control 控制反转 ioc是通过DI实现的 IOC让对象的**创建与管理职责由容器负责**,而不是由对象自身控制 + +`核心思想`: 对象的创建和依赖不是由对象本身实现的 而是由Spring容器管理的 + +好处: `灵活性 解耦` + +DI (依赖注入dependency injection )通过`构造器、setter方法、接口注入` 将对象的依赖项传递给他 而不是对象自行创建依赖. + + + +扩展:IOC 只是一个思想 + +控制的是什么?? 控制的是` 对象的创建 ` + + 反转的是什么?? 反转的是 `创建对象且注入依赖对象的这个动作` + +反转之前 是我们在一个类里面new一个类 这个类的创建是我们创建的 + +而现在类的生命周期是由Spring控制的了 + +ex:Spring容器使用了工厂模式为我们创建了所需要的对象,我们使用时不需要自己去创建,直接调用Spring为我们提供的对象 +即可,这就是控制反转的思想。 + + + +**好处** + +例如,对象 A 需要依赖一个实现 B,但是对象都由 IOC 控制之后,我们不需要明确地在对象 A 的代码里写死依赖的实现 B,只需要写明依赖一个接口,这样我们的代码就能顺序的编写下去。 然后,我们可以在配置文件里定义 A 依赖的具体的实现 B,根据配置文件,在创建 A 的时候,IOC 容器就知晓 A 依赖的 B,这时候注入这个依赖即可。 如果之后你有新的实现需要替换,那 A 的代码不需要任何改动,你只需要将配置文件 A 依赖 B 改成 B1,这样重启之后,IOC 容器会为 A 注入 B1。 + + + +## Spring IOC容器初始化过程 + +### 启动阶段 + +- 配置加载:加载配置文件或者配置类 +- 创建容器:Spring 创建IOC容器(Beanfactory ApplicationContext)准备加载和管理Bean文件 + +### Bean注册阶段 + +- 解析和注册:BeanDefinitionReader读取配置中的Bean定义,并将其注册到容器中,形成BeanDefinition对象 + +### 实例化和依赖注入 + +- 实例化: 根据BeanDefinition创建Bean实例 +- 依赖注入:根据BeanDefinitio中的依赖关系,可以通过 构造注入 setter注入 或者字段注入 将依赖注入到Bean里面 + +### 初始化 + +- BeanPostProcessor处理 这些处理器会在Bean初始化生命周期中加入定义的处理逻辑 +- Aware接口调用 如果Bean实现了Aware接口(BeanNameAware BeanFactoryAware) Spring会回调这些接口,传递容器相关的信息 +- 初始化方法调用:调用Bean的初始化方法 + + + +## 什么是Bean + +任何通过Spring容器实例化的 组装和管理的JAVA对象都可以称为bean + +**Bean定义方式** + +1. XML ->就是 + + ```xml + + id就是你给他定义的名字 class就是路径名字 + ``` + + + +2. 注解 + + ```java + @C@Component + @Controlle + @Service + @Repository + ``` + + + +3. java配置类 + +```java +@Configuration +@ComponentScan("pers.mobian.firstTest") +public class ContextConfig { +} + + +@Configuration +public class Config { + + @Bean(name = "mobian666") + public MoBian moBian(){ + return new MoBian(); + } +} +``` + + + +## 什么是BeanFactory + +Bean工厂 创建和管理Bean的 底层就是Ioc容器 + +负责从配置源 XML java配置类 注解之类的读取Bean的定义 负责她的生命周期 + +**延迟加载** -》延迟初始化 只有在Bean首次请求的时候才会实例化这个Bean 而不是程序已启动就开始 + + + +## FactoryBean + +FactoryBean 可以自定义任何所需的初始化逻辑,生产出一些定制化的 bean,简单来说就是 可以封装Bean + +**FactoryBean 与普通 Bean 的区别** + +- **创建逻辑不同**:普通的 Bean 直接由 Spring 容器管理,而 FactoryBean 通过自定义的 `getObject()` 方法创建实际的对象。 +- **动态代理和复杂对象**:FactoryBean 适用于创建动态代理或复杂的 Bean,而普通 Bean 通常只处理简单的对象创建。 + + + +想要成为FactoryBean需要实现 + +```java +public class SqlSessionFactoryBean implements FactoryBean { + @Override + public SqlSessionFactory getObject() throws Exception { + // 创建并配置 SqlSessionFactory(如加载 MyBatis 配置、数据源等) + return new SqlSessionFactoryBuilder().build(config); + } +} + +``` + + + + + +## Bean的作用域 + +**singleton**:默认是单例,含义不用解释了吧,一个IoC容器内部仅此一个 + +**prototype**:原型,多实例 + +**request**:每个请求都会创建一个属于自己的Bean实例,这种作用域仅存在Spring Web应用中 + +**session**:一个Http Session 中有一个bean的实例,这种作用域仅存在Spring Web应用中 + +**application**:整个ServletContext生命周期里,只有一个bean,这种作用域仅存在Spring Web应用中 + +**websocket**: 一个WebSocket生命周期内一个bean实例,这种作用域仅存在Spring Web应用中 + +## 什么是AOP(切面编程) + +是什么?: 其实就是将与业务无关的一些东西 比如(log 权限校验 安全检查 之类的)与业务逻辑分开 + +**AOP(面向切面编程)的核心**是将日志、事务、权限等与业务逻辑无关的**横切关注点**从业务代码中抽取出来,通过声明式的方式动态应用到业务方法中,避免这些逻辑直接嵌入业务代码导致的冗余与耦合。 + +**主要组成部分** 切面 连接点 通知 切入点 织入 + + + +**AOP是通过动态代理来实现的** + +动态代理:运行时 将切面的逻辑放入 + +静态代理:编译期间/类加载期间 + + + +Aop的核心概念 + +- **Aspect**:切面,只是一个概念,没有具体的接口或类与之对应,是 Join point,Advice 和 Pointcut 的一个统称。 + + - ```java + @Aspect + public class LoggingAspect { + @Before("execution(* com.example.service.*.*(..))") + public void logBefore() { + System.out.println("Logging before method execution"); + } + } + + ``` + + + +- **Join point**:连接点,指程序执行过程中的一个点,例如方法调用、异常处理等。在 Spring AOP 中,仅支持方法级别的连接点。 + +- **Advice**:通知,即我们定义的一个切面中的横切逻辑,有“around”,“before”和“after”三种类型。在很多的 AOP 实现框架中,Advice 通常作为一个拦截器,也可以包含许多个拦截器作为一条链路围绕着 Join point 进行处理。 + +- **Pointcut**:切点,用于匹配连接点,一个 AspectJ 中包含哪些 Join point 需要由 Pointcut 进行筛选。 + + - ```java + @Pointcut("execution(* com.example.service.*.*(..))") + public void serviceMethods() {} + ``` + +- **Introduc** + +- **tion**:引介,让一个切面可以声明被通知的对象实现任何他们没有真正实现的额外的接口。例如可以让一个代理对象代理两个目标类。 + +- **Weaving**:织入,在有了连接点、切点、通知以及切面,如何将它们应用到程序中呢?没错,就是织入,在切点的引导下,将通知逻辑插入到目标方法上,使得我们的通知逻辑在方法调用时得以执行。 + + + +## SpringAOP 默认是什么动态代理 + +Spring Framework 默认的是 JDK动态代理 SB 2x了以后 就是CGLIB + +区别 + +**代理方式** + +- JDK动态代理 基于**接口实现** 通过Proxy动态生成代理类 +- CFLIB动态代理**基于类继承**,通过字节码技术生成目标类的子类 + +**使用场景** + +- JDK动态代理 推荐用于`代理接口`的场景 适合代理的类实现了接口 +- CGLIB动态代理 适合没有接口的类。`基于继承实现的` + + + +## Spring 拦截连的实现 + +什么是拦截链 指一系列拦截器以此作用于请求或方法调用 实现横切关注点的处理 + +**主要方面** + +- `HandlerInterceptor `(MVC拦截器) 用于拦截HTTP 请求并经行处理 实现`preHandle postHandle afterCompletion` 来实现拦截前中后 的方法 +- `Filter` 基于servlet API 的过滤器 用于处理 跨域 安全验证 编码过滤 通过*`doFilter`*方法拦截请求 +- `Aop切面` Spring AOP 提供的方法级别的拦截,通过定义切面(Aspect)可以实现方法的前后处理。切面中的` @Before、@After、@Around` 等注解用于控制拦截的执行顺序。 + +这个底层的源码就是 + +有一个chain集合 这个集合里面存放着所有的interceptor的方法 然后每次通过index++来调取下一个方法 这个方法 被cglibmethodinvocation封装起来在proceed方法 + + + + + +## AOP与AspectJ有什么区别 + +- Aop 基于**动态代理** 在**运行时**的代理机制 + + - 轻量级 的SpringBean容器 + - 适合大部分的业务场景 尤其是简单的AOP功能的Spring应用 + + AspectJ 更加强大 + + - 支持编译时 类加载时 运行时的AOP功能 + - 支持更加灵活的切点和增强操作,提供编译期和加载期的织入方式,性能较高。 + - 适合对性能要求较高或需要复杂切点匹配的场景,如日志、监控等。 + + + +## SpringMVC + +M model 模型 + +V view 试图 + +C controller 控制 + +核心就是**DispatchServlet** 前端控制器。它通过注解、配置等方式 将Http的请求 映射到控制器方法中去 然后由Controller处理请求逻辑 并将数据返还给View层去渲染 + + + +Spring MVC 的工作流程可以分为以下几个关键步骤: + +**客户端请求**:浏览器向服务器发送 HTTP 请求。 + +**DispatcherServlet**:所有的请求首先由 Spring MVC 的核心前端控制器 `DispatcherServlet` 接收,它充当整个流程的调度中心。 + +- ```java + @Controller --> 标记控制类 + public class MyController { + @RequestMapping("/login") --> 方法和url的映射关系 + public String mianshiya() { + return "哈哈哈"; + } + } + + ``` + + + +**处理器映射(Handler Mapping)**:`DispatcherServlet` 根据请求的 URL 使用处理器映射器找到对应的控制器(Controller)。 + +**控制器(Controller)**:控制器接收请求并处理业务逻辑,通常通过注解 `@Controller` 和 `@RequestMapping` 定义请求的映射方法。 + +**模型和视图(ModelAndView)**:控制器处理完业务逻辑后,将数据封装到模型对象中,并指定返回的视图名称。 + +**视图解析器(ViewResolver)**:`DispatcherServlet` 调用视图解析器,将逻辑视图名称解析为实际的视图,如 JSP、Thymeleaf 等模板引擎。 + +- ```java + @Bean + public InternalResourceViewResolver viewResolver() { + InternalResourceViewResolver resolver = new InternalResourceViewResolver(); + resolver.setPrefix("/WEB-INF/views/"); + resolver.setSuffix(".jsp"); + return resolver; + } + //InternalResourceViewResolver等等就是一个视图解析器 + + + @RequestMapping("/user") + public String getUser(@RequestParam("id") String userId) { + // 使用请求参数 + } + + @RequestMapping("/user/{id}") + public String getUserById(@PathVariable("id") String userId) { + // 使用路径变量 + } + //@RequestParam获取请求参数 + //@PathVariable 获取url的路径的变量 + ``` + + + +**视图渲染**:视图渲染引擎根据模型中的数据生成 HTML 页面并返回给客户端。 + + + +### 表单处理 & 数据绑定 + +数据绑定 就是通过`@ModelAttribute` 自动的将表单数据绑定到数据模型上面 + +```java +@RequestMapping("/submitForm") +public String submitForm(@ModelAttribute("user") User user) { + // 处理表单提交的数据 + return "result"; +} + +``` + +表单校验 + +通过 `@Valid` 和`BindingResult` 可以处理表单之前就进行数据数据处理 + +```java +@RequestMapping("/submitForm") +public String submitForm(@Valid @ModelAttribute("user") User user, BindingResult result) { + if (result.hasErrors()) { + return "form"; + } + return "result"; +} + +``` + +### 全局异常处理 + +通过` @ControllerAdvice `和 ` @ExceptionHandler(Exception.class)` 处理全局的异常 + +```java +@ControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(Exception.class) + public String handleException(Exception ex) { + // 处理异常 + return "error"; + } +} +``` + +image-20251025211652863 + + + +## Spring中的设计模式 + +image-20251025213007518 + +image-20251025213031184 + +## 脏读 不可重读 幻读 + +脏读(Dirty Read):一个事务**读取**了**另一个尚未提交**的事务的数据,如果该事务回滚,则数据是不一致的。 + +不可重复读(Non-repeatable Read):因为**其他事务修改了该数据并提交**,所以 在同一事务内的多次读取,前后数据不一致,。 + +幻读(Phantom Read):在一个事务内的多次查询,查询结果集不同,因为其他事务插入或删除了数据。 + + + +不可重复读 是在读的事务中,其他事务update提交了。 + +幻读 是在读的事务中,其他事务进行了insert或者delete。 + +## 事务隔离级别 + +### DEFAULT(默认) + + 默认通常为默认 + +### READ_UNCOMMITTED(读未提交) + +- 最低的隔离级别 +- 允许事务**读取**`尚未提交`的数据 +- 可能会导致脏读、不可重读、幻读 + +### READ_COMMITTED(读已提交) + +- 仅次于上面那位 +- 仅允许读取已经提交的数据 +- `避免了脏读` 但是还是**不可重读、幻读**有可能实现 + +### PEREATABLE_RAED(可重复读) + +- 仅次于上面那位 +- 确保在同一个事务内的``多次读取结果一致`` +- `避免脏读和不可重复读`,但可能会有**幻读问题** + + + +### SERIALIZABLE(可串行化) + +- 最屌的那位 +- 通过强事务按顺序执行 +- 避免了所有的问题 + +image-20251027170227931 + + + + + + + +```java +@Transactional(isolation = Isolation.REPEATABLE_READ) +public void processTransaction() { + // 事务逻辑 +} +``` + + + + + +## 事务的传播级别 + +前言:什么是传播? + +就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。比如说,A事务方法调用了B事务方法,B是继续在调用者A的事务中运行呢?还是为自己另开一个新事物运行? 这就是由B的事务传播行为决定的。 + +正常来说有几种解决方案: + +1. 融入事务:直接去掉 serviceB 中关于开启事务和提交事务的 begin 和 commit,融入到 serviceA 的事务中 (直接用 ServiceA 的事务)。问题: B 事务的错误会引起 A 事务的回滚。 +2. 挂起事务:如果不想 B 事务的错误引起 A 事务的回滚,可以开启两个连接,一个执行 A 一个执行 B,互不影响,执行到 B 的时候把 A 挂起新起连接去执行 B,B 执行完了再唤醒 A 执行。 +3. 嵌套事务: MySQL 中可以通过给 B 事务加 savepoint 和 rollback 去模拟嵌套事务,把 B 设置成伪事务。 + +spring 中的事务传播行为: + +1. PROPAGATION_REQUIRED (需要): + - 需要事务。 + - 如果存在一个事务,则直接使用当前事务。如果则开启一个新的事务。(A 如果存在事务,则 B 融入 A 事务,如果没有则新起一个事务) +2. SUPPORTS (支持): + - 支持 A 的事务。 + - 如果存在一个事务,支持当前事务。如果则非事务的执行。(A 有,则 B 融入,A 没有,则非事务执行) +3. MANDATORY (强制性): + - 强制什么? + - 强制必须有事务。如果已经当前存在一个事务,使用当前事务。没有则抛出异常。(A 有,则 B 融入,A 没有,则抛异常) +4. REQUIRES_NEW (需要新的): + 1. 如果一个事务已经存在,则先将这个存在的事务挂起。 + 2. 如果没有,则新起一个事务执行。(A 有,则将 A 事务挂起,新开一个事务来执行 B,执行完后,唤醒 A,继续执行;A 没有事务则新起一个事务执行 B) +5. NOT_SUPPORTED (不支持): + 1. 不支持什么?不支持事务。 + 2. 总是非事务地执行,并挂起任何存在的事务。(A 有,则挂起 A,B 非事务执行,执行完之后,唤醒 A,A 继续执行,A 还是以事务形式执行的) +6. NEVER (从不): + 1. 总是非事务地执行, + 2. 如果存在一个活动事务,则抛出异常。(A 有,则抛异常) +7. NESTED (嵌套的): + 1. 如果一个活动的事务存在,则运行在一个嵌套的事务中。 + 2. 如果没有活动事务,则按 TransactionDefinition.PROPAGATION_REQUIRED 属性执行。(A 有,则 B 用 savepoint 方式嵌套执行与 A) + +## 事务的传播有什么用 + +1. 控制事嵌套和传播 +2. 确保独立操作的事务隔离 +3. 控制事务的边界的一致性 + + + +image-20251027180538746 + + + +## SpringAOP技术的相关术语 + +### 切面 + +切面是将通知应用到切入点的过程。切面通常由通知和切入点组成,用于定义增强逻辑的执行范围。 + +```java +@Aspect +public class LoggingAspect { + + @Before("addPointcut()") + public void logBeforeAdd() { + System.out.println("前置通知:方法执行前"); + } + + @After("addPointcut()") + public void logAfterAdd() { + System.out.println("后置通知:方法执行后"); + } +} +``` + + + +### 通知 + +通知是指在连接点上执行的增强逻辑。 + +- **前置通知**:在方法执行之前执行。 + +- **后置通知**:在方法执行之后执行。 + +- **环绕通知**:在方法执行前后都可以执行。 + +- **异常通知**:在方法抛出异常时执行。 + +- **最终通知**:在方法正常返回时执行。 + +- ```java + @Around("addPointcut()") + public Object aroundAdd(ProceedingJoinPoint joinPoint) throws Throwable { + System.out.println("环绕通知:方法执行前"); + Object result = joinPoint.proceed(); // 执行目标方法 + System.out.println("环绕通知:方法执行后"); + return result; + } + ``` + + + +### 切点 + +切入点是指我们实际增强的连接点。在Spring AOP中,切入点是通过表达式定义的,用于指定哪些连接点需要被增强。 + +```java +@Pointcut("execution(* com.example.User.add(..))") +public void addPointcut() {} + +@Pointcut("execution(* com.example.User.delete(..))") +public void deletePointcut() {} +``` + + + +### 连接点 + +连接点是指程序执行过程中可以被增强的点。在Spring AOP中,连接点通常是指方法的执行点。 + +假设我们有一个`User`类,其中包含四个方法:`add()`、`update()`、`select()`和`delete()`。这些方法都可以被增强,因此它们都是连接点。 + +```java +public class User { + public void add() { + System.out.println("执行添加方法"); + } + + public void update() { + System.out.println("执行更新方法"); + } + + public void select() { + System.out.println("执行查询方法"); + } + + public void delete() { + System.out.println("执行删除方法"); + } +} +``` + +### 目标对象 + +给谁加 就谁是目标对象 很好理解 + +### 代理 + +- JDK动态代理 +- CGLIB代理 + +### 织入 + +织入是将切面应用到目标对象的过程。织入可以发生在编译时、类加载时或运行时。在 Spring 中,AOP 的织入通常发生在运行时。 + +- 使用 `@Aspect` 注解标记的类,会在运行时通过代理方式将切面织入目标类。 + + + + + +| 问题 | 答案 | +| ------------------------------ | ------------------------------------------------------------ | +| Q1: 什么是连接点? | A1: 连接点是指程序执行过程中可以被增强的点,通常是指方法的执行点。 | +| Q2: 切入点和连接点有什么区别? | A2: 连接点是程序中所有可以被增强的点,而切入点是指实际增强的连接点。 | +| Q3: 通知有哪些类型? | A3: Spring AOP支持五种类型的通知:前置通知、后置通知、环绕通知、异常通知、最终通知。 | +| Q4: 切面的作用是什么? | A4: 切面是将通知应用到切入点的过程,用于定义增强逻辑的执行范围。 | +| Q5: 如何定义切入点? | A5: 通过Spring AOP的表达式语言(如`execution()`)定义切入点。 | + + + + + + + +## SPringBean 注册到容器的方式 + +- XML + +- @Compoenet + + - @Service@Controller@Repository是@Component行生注解 + +- @Configuration 和 @Bean + + - ```java + @Configuration//声明配置类 + public class AppConfig { + + @Bean + public MyBean myBean() { + return new MyBean(myDependency()); + } + + @Bean + public MyDependency myDependency() { + return new MyDependency(); + } + } + + ``` + + + +- @Import注解 + +- ```java + @Configuration + @Import(MyComponent.class) + public class MainConfig { + // 当前配置类逻辑 + } + + public class MyComponent { + // 普通类逻辑 + } + + ``` + + + + + +## 自动装配 + +### no 默认装配 + +默认方式 不进行自动装配 依赖关系必须显式定义 + +```xml + + + + + +``` + + + +### byName + +根据名字定义 + +```xml + + + +``` + + + +### byType + +要求容器中有且仅有一个符合类型的Bean + +```xml + + + +``` + + + +### constructor + +```xml + + + +``` + + + +## @Conponent @Controller @Service @Repository + + @Controller @Service @Repository都是@Conponent的衍生注解 + +@component:这是一个通用的注解,用于将任意类注册为 Spring 容器中的 Bean。它没有特定的语义,适用于任何需要 Spring 管理的类 + +@contro11er:这是一个专门用于 Spring MVC 中的控制器(Controler)层的注解。用于处理 HTTP 请求,并将结果返回给客户端。 + +@service:用于标识业务逻辑层的类。它具有明确的语义,表明该类承担业务操作,主要用于编写服务类 +@Repository:用于数据访问层(DAO)的类,与数据库交互。 + +```java +@Repository +public class UserRepository { + + public User findUserById(Long id) { + // 从数据库中查询用户 + return new User("John", "Doe"); + } +} + +``` + + + +## Spring启动过程 + +1. 加载配置文件 初始化文件 +2. 实例化文件 + - 根据配置中的信息创建文件 ApplicationContext + - 实例化BeanFactory 并且加载容器中的BeanDefination +3. 解析BeanDefination +4. 实例化Bean +5. 注入依赖 +6. 处理Bean的生命周期 +7. 处理BeanPostProcessor +8. 发布事件 +9. 完成启动 + + + + + diff --git a/面试/八股文/image-20251024143700377.png b/面试/八股文/image-20251024143700377.png new file mode 100644 index 0000000..6fb5545 Binary files /dev/null and b/面试/八股文/image-20251024143700377.png differ diff --git a/面试/八股文/image-20251024152138996-1761290506783-1.png b/面试/八股文/image-20251024152138996-1761290506783-1.png new file mode 100644 index 0000000..9688bc5 Binary files /dev/null and b/面试/八股文/image-20251024152138996-1761290506783-1.png differ diff --git a/面试/八股文/image-20251024154932330.png b/面试/八股文/image-20251024154932330.png new file mode 100644 index 0000000..a81669d Binary files /dev/null and b/面试/八股文/image-20251024154932330.png differ diff --git a/面试/八股文/image-20251024160334418.png b/面试/八股文/image-20251024160334418.png new file mode 100644 index 0000000..af78625 Binary files /dev/null and b/面试/八股文/image-20251024160334418.png differ diff --git a/面试/八股文/image-20251024161935634.png b/面试/八股文/image-20251024161935634.png new file mode 100644 index 0000000..012d2fc Binary files /dev/null and b/面试/八股文/image-20251024161935634.png differ diff --git a/面试/八股文/image-20251024164026531.png b/面试/八股文/image-20251024164026531.png new file mode 100644 index 0000000..9093ff0 Binary files /dev/null and b/面试/八股文/image-20251024164026531.png differ diff --git a/面试/八股文/image-20251024183530002.png b/面试/八股文/image-20251024183530002.png new file mode 100644 index 0000000..c6b0c17 Binary files /dev/null and b/面试/八股文/image-20251024183530002.png differ diff --git a/面试/八股文/image-20251025125111136.png b/面试/八股文/image-20251025125111136.png new file mode 100644 index 0000000..4d3bc2d Binary files /dev/null and b/面试/八股文/image-20251025125111136.png differ diff --git a/面试/八股文/image-20251025163127819.png b/面试/八股文/image-20251025163127819.png new file mode 100644 index 0000000..c0213d0 Binary files /dev/null and b/面试/八股文/image-20251025163127819.png differ diff --git a/面试/八股文/image-20251025163843482.png b/面试/八股文/image-20251025163843482.png new file mode 100644 index 0000000..13f84af Binary files /dev/null and b/面试/八股文/image-20251025163843482.png differ diff --git a/面试/八股文/image-20251025211652863.png b/面试/八股文/image-20251025211652863.png new file mode 100644 index 0000000..3fbeeda Binary files /dev/null and b/面试/八股文/image-20251025211652863.png differ diff --git a/面试/八股文/image-20251025213007518.png b/面试/八股文/image-20251025213007518.png new file mode 100644 index 0000000..f2fe123 Binary files /dev/null and b/面试/八股文/image-20251025213007518.png differ diff --git a/面试/八股文/image-20251025213031184.png b/面试/八股文/image-20251025213031184.png new file mode 100644 index 0000000..1200061 Binary files /dev/null and b/面试/八股文/image-20251025213031184.png differ diff --git a/面试/八股文/image-20251027164300265.png b/面试/八股文/image-20251027164300265.png new file mode 100644 index 0000000..7d8c0e9 Binary files /dev/null and b/面试/八股文/image-20251027164300265.png differ diff --git a/面试/八股文/image-20251027170227931.png b/面试/八股文/image-20251027170227931.png new file mode 100644 index 0000000..730753e Binary files /dev/null and b/面试/八股文/image-20251027170227931.png differ diff --git a/面试/八股文/image-20251027180538746.png b/面试/八股文/image-20251027180538746.png new file mode 100644 index 0000000..c65097c Binary files /dev/null and b/面试/八股文/image-20251027180538746.png differ diff --git a/面试/八股文/image-20251028191927109.png b/面试/八股文/image-20251028191927109.png new file mode 100644 index 0000000..f998e84 Binary files /dev/null and b/面试/八股文/image-20251028191927109.png differ diff --git a/面试/八股文/image-20251028194534789.png b/面试/八股文/image-20251028194534789.png new file mode 100644 index 0000000..a476b3a Binary files /dev/null and b/面试/八股文/image-20251028194534789.png differ diff --git a/面试/八股文/image-20251028220439394.png b/面试/八股文/image-20251028220439394.png new file mode 100644 index 0000000..4dea991 Binary files /dev/null and b/面试/八股文/image-20251028220439394.png differ diff --git a/面试/八股文/image-20251030165732479.png b/面试/八股文/image-20251030165732479.png new file mode 100644 index 0000000..60b5110 Binary files /dev/null and b/面试/八股文/image-20251030165732479.png differ diff --git a/面试/八股文/image-20251106152729662.png b/面试/八股文/image-20251106152729662.png new file mode 100644 index 0000000..2d76097 Binary files /dev/null and b/面试/八股文/image-20251106152729662.png differ diff --git a/面试/八股文/image-20251109195036812.png b/面试/八股文/image-20251109195036812.png new file mode 100644 index 0000000..20203cd Binary files /dev/null and b/面试/八股文/image-20251109195036812.png differ diff --git a/面试/八股文/image-20251110202641289.png b/面试/八股文/image-20251110202641289.png new file mode 100644 index 0000000..cdd13dc Binary files /dev/null and b/面试/八股文/image-20251110202641289.png differ diff --git a/面试/八股文/image-20251110202708473.png b/面试/八股文/image-20251110202708473.png new file mode 100644 index 0000000..cfa761b Binary files /dev/null and b/面试/八股文/image-20251110202708473.png differ diff --git a/面试/八股文/image-20251111214414297.png b/面试/八股文/image-20251111214414297.png new file mode 100644 index 0000000..e9165ca Binary files /dev/null and b/面试/八股文/image-20251111214414297.png differ diff --git a/面试/八股文/java.md b/面试/八股文/java.md new file mode 100644 index 0000000..172ba14 --- /dev/null +++ b/面试/八股文/java.md @@ -0,0 +1,170 @@ +## [java新特性]() + +### java8 + +- **用元空间替代了永久代** + +- **引用了Lambda表达式** + +- **函数式接口** + + - Predicate ->条件判断 + + - ```java + // Predicate 用于条件判断 + Predicate isEven = n -> n % 2 == 0; + Predicate isEmpty = String::isEmpty; + Predicate isNotEmpty = isEmpty.negate(); // 取反 + + List numbers = Arrays.asList(1, 2, 3, 4, 5, 6); + List evenNumbers = numbers.stream() + .filter(isEven) + .collect(Collectors.toList()); + + ``` + + - Function 数据转换 + + - ```java + // Function 用于转换 + Function stringLength = String::length; + Function intToString = Object::toString; + + // 函数组合 + Function addPrefix = s -> "前缀-" + s; + Function addSuffix = s -> s + "-后缀"; + Function combined = addPrefix.andThen(addSuffix); + String result = combined.apply("鱼皮"); // "前缀-鱼皮-后缀" + + ``` + + + +- **引入了日期类** + + - 从原来的Date&Calendar 引入新的LoacalDate + - 解决了一些旧日历的线程安全..可变性...之类的 + +- **接口默认方法、静态方法** + + - **接口升级**:比如 `Java 8` *中对 `Collection` 接口新增了 `stream()` 等默认方法,所有集合实现类(如 `ArrayList`、`HashMap`)无需修改即可直接使用这些方法。 + - **提供通用实现**:接口中可以定义通用逻辑的默认方法,减少实现类的重复代码。 + +- **新增Stream流式接口** + + - 新增一些中间的stream API 能够让对集合的处理更加的`优雅` + - filter() + - map() + - sorted() + - distinct() + - limit() + - skip() + - 也有一些终端的操作 让 + - collection() + - foreach() + - count() + - findFirst() + - anyMatch()//是否有匹配的 + - reduce()//归约操作 + +- **引入Optional类** + +- **新增了CompletableFuture,StampedLock...并发实现类** + + + +### java11 + +- HTTP客户端的API + +- String类的新特性 + + - isBlank()-->判空 + - strip() -->出去空白字符 + - lines()-->将字符串分割成Stream + - repeat()-->重复字符串 + +- File类 + +- 改进了原先难用的FileReader FileWriter + + - ```java + // 写入文件 Files.writeString + String content = "这是一个测试文件\n包含多行内容\n中文支持测试"; + Path tempFile = Files.writeString( + Paths.get("temp.txt"), + content, + StandardCharsets.UTF_8 + ); + + // 读取文件 Files.readString + String readContent = Files.readString(tempFile, StandardCharsets.UTF_8); + System.out.println("读取的内容:\n" + readContent); + + ``` + + + +### java17 `代码设计安全性` `JDK稳定性` + +- **虚拟线程** + + - 传统的线程 每一个线程都对应着一个真实的线程 那么 虚拟线程 就可以 栈内存按需分配(初始可小至 KB 级),创建 / 销毁成本极低。 + + - 可轻松创建百万甚至千万级 + + - 由 JVM 的**虚拟线程调度器**管理,最终映射到平台线程执行。 + + - 使用简单 + + - ```java + // 直接创建虚拟线程 + public void handleSingleUser(Long userId) { + Thread.ofVirtual().start(() -> { + // 要异步执行的任务 + User user = userService.findById(userId); + processUser(user); + }); + } + + ``` + + - **Switch匹配方式重大跟新** + + - 支持条件判断 + - 可以匹配对象类型 然后直接转换 优雅~~ + + - **Record模式(不想看 极简化不是我的代码风格)** + + - 记住一次性可以提取所有的信息即可 + + + +### java25 + +- **Scoped** **Value** + - 这个方法允许在`线程`内以及`子线程`之间安全高效的`共享不可变数据` + - 并且开销小 why + - 因为是这样的比如一个线程里面有一个资源 你开1000个 总不能复制1000个吧 不然太慢了 所以ScopedValue 就是为了不让复制1000个而产生的 + + + + + +## 双亲委派模型 + +**Def**:当类加载器 去加载某个类的时候 会委派父类加载器 ---直到->根类加载器 BootStrap ClassLoader ,当父类的无法加载时 才给本类加载 + +**为了什么?:** + +1. 安全性 比如java.lang.object 只能由根类加载器使用 因此如果有人替换了Object也没事 、 +2. 一致性 保证一个类在JVM中只会被加载一次 让我们每次用的都是用一个类对象 +3. image-20251024152138996 + + 三种类加载器 + +1. 启动类加载器 --》虚拟机的一部分 由C++实现的 负责加载\lib 目录中或被 -Xbootclasspath 指定的路径中的并且文件名是被虚拟机识别的文件。 +2. 扩展类加载器--》java实现的,独立于虚拟机 负责加载 \lib\ext 目录中或被 java.ext.dirs 系统变量所指定的路径的类库。 +3. 应用程序类加载器--》java实现的,独立于虚拟机 主要负责加载用户类路径 ( classPath ) 上的类库,如果我们没有实现自定义的类加载器那这玩意就是我们程序中的默认加载器。 + + diff --git a/面试/八股文/并发.md b/面试/八股文/并发.md new file mode 100644 index 0000000..46504eb --- /dev/null +++ b/面试/八股文/并发.md @@ -0,0 +1,254 @@ +## JMM + +JMM 是专门解决多线程并发问题的一套规则 + +核心就是`可见性、原子性、有序性` + +可见性: 像volatile关键字 就是保证了 所有线程见到的数据是一样的 + +原子性:JMM 里用 synchronized 或者 Lock 锁就能保证原子性 保证了一个程序的步骤不会被打断 + +有序性:编译器或者 CPU 为了提速,会在不影响单线程结果的情况下调整指令顺序。但多线程下,另一个线程拿到 a 的引用时,A 可能还没初始化好,一调用就报错。这时候 volatile 或者 synchronized 就能通过内存屏障阻止这种重排序,保证顺序正确。 + + + + + +## 如何保证数据的一致性 + +- 事务管理 + - 数据库的事务 + - 读未提交 读已提交 可重复读 串行化 +- 锁机制 + - sychornized ReenrantLock +- 版本控制 + - 通过乐观锁的方式 在更新数据时记录版本信息 + + + +## 线程创建的方法 + +1. 继承`Thread`类 然后通过`run`方法 使用的话 就是.start() + +2. 实现Runnable接口 重写`run`方法 + +3. 实现Callable接口与FutureTask + + 1. ```JAVA + class MyCallable implements Callable { + @Overridepublic Integer call() throws Exception { + // 线程执行的代码,这里返回一个整型结果return 1;}} + public static void main(String[] args) { + MyCallable task = new MyCallable(); + FutureTask futureTask = new FutureTask<>(task); + Thread t = new Thread(futureTask);t.start(); + try {Integer result = futureTask.get(); + // 获取线程执行结果 + System.out.println("Result: " + result);} + catch (InterruptedException | ExecutionException e) + { + e.printStackTrace(); + } + } + ``` + + + +4. 使用线程池(Executor框架) + + + +## Sleep和wait的区别 + +image-20251028191927109 + + + + + +## blocked和waiting有啥区别 + +`blocked` + +- 主要是因为sychon了没有抢到锁 导致进入了blocked +- blocked可以通过获得锁 主动的唤醒 + +`waiting` + +- 线程进入WAITING状态是因为它正在等待另一个线程执行某些操作,例如调用Object.wait()方法、Thread.join()方法或LockSupport.park()方法。在这种状态下,线程将不会消耗CPU资源,并且不会参与锁的竞争 +- waiting主要是通过主动的唤醒 notify + + + +## notify 和 notifyAll 的区别? + +同样是唤醒等待的线程,同样最多只有一个线程能获得锁,同样不能控制哪个线程获得锁。 区别在于: + +- notify:唤醒一个线程,其他线程依然处于wait的等待唤醒状态,如果被唤醒的线程结束时没调用notify,其他线程就永远没人去唤醒,只能等待超时,或者被中断 +- notifyAll:所有线程退出wait的状态,开始竞争锁,但只有一个线程能抢到,这个线程执行完后,其他线程又会有一个幸运儿脱颖而出得到锁 + + + +## 如何停止一个线程 + +**核心**:通过协作式的逻辑控制线程中止 + +1. 通过共享标志位主动停止 就是线程控制一个公共的变量 然后通过那个变量来关闭线程 +2. 线程中断机制 `Thread.interrupt()` +3. 通过`Future`取消任务 Future.cancel() +4. 资源关闭 + +image-20251028194534789 + +# + + + + + +# 并发安全 + +## JUC包常用的类 + +### 线程池相关 + +- `**ThreadPoolExecutor **` **最核心的线程池类** 用于创建和管理线程池 通过它可以灵活地配置线程池的参数,如核心线程数、最大线程数、任务队列等,以满足不同的并发处理需求。 +- **Executor **线程池工厂类 提供了一系列的方法来创建不同类型的线程池 + +### 并发集合类 + +- **ConcurrentHashMap **线程安全的哈希表 允许多个线程同时访问不同的段,提高了并发性能,在高并发场景下比传统的`Hashtable`性能更好。 +- **CopyOnWriteArrayList **线程安全的列表将修改操作应用到新数组上而读操作仍然可以在旧数组上进行,从而实现了读写分离提高了并发读的性能`,适用于读多写少的场景。` + +### 同步工具类 + +- **CountDownLatch** 允许一个或多个线程等待其他一组线程完成操作后再继续执行。 就是通过一个计数器 每次用完以后 调用**countDown ** 就-1当计数器为零时,等待的线程可以继续执行。常用于多个线程完成各自任务后,再进行汇总或下一步操作的场景。 +- **CyclicBarrier** `可以重复使用`当所有线程都通过屏障后,计数器会重置,可以再次用于下一轮的等待。 +- **Semaphore **信号量,用于控制同时访问某个资源的线程数量。 + +### 原子类 + +- **AtomicInteger **原子整数类,提供了对**整数类型的原子操作** +- **AtomicReference** 原子引用类,用于对 **对象引用**进行原子操作。 + + + +### 怎么保证多线程安全? + +- **synchronized关键字**: 同步代码块或方法 + +- **volatile关键字**: `volatile`关键字用于变量,确保所有线程看到的是该变量的最新值 + +- **Lock接口和ReentrantLock类**: `Lock`接口提供了比`synchronized`更强大的锁定机制 `ReentrantLock`是一个实现该接口的例子,提供了更灵活的锁管理和更高的性能。 + +- **原子类** `ReentrantLock`是一个实现该接口的例子,提供了更灵活的锁管理和更高的性能。 + +- ```java + AtomicInteger counter = new AtomicInteger(0); + int newValue = counter.incrementAndGet(); + ``` + + + +- **线程局部变量** + +`ThreadLocal`类可以为每个线程提供独立的变量副本, 这样每个线程都拥有自己的变量,消除了竞争条件。 + +```java +ThreadLocal threadLocal new ThreadLocal<>(); +threadLocal.set(数值) +int value = threadLocalVar.get(); +``` + + + +- **并发集合** + +CopyOnWriteArrayList ConcurrentHashMap 等 就是自己就是实现了线程安全的集合 + +- **JUC工具类**: + +工具类可以用于控制线程间的同步和协作。 Semaphore`和`CyclicBarrier + + + + + +## java常见的锁 + +- **内置锁(synchronized)** + - 当一个线程进入`synchronized`代码块或方法时,它会获取关联对象的锁;当线程离开该代码块或方法时,锁会被释放。如果其他线程尝试获取同一个对象的锁,它们将被阻塞,直到锁被释放。 + - 分类 **无锁、偏向锁、轻量级锁和重量级锁** + - 无锁 + - 偏向锁 当一个线程进入同步块时,如果没有任何其他线程竞争,就会使用偏向锁 **以减少锁的开销** + - 轻量级锁 使用线程`栈`上的数据结构,避免了操作系统级别的锁。 + - 重量级锁 涉及``操作系统级``的互斥锁。 +- **ReentrantLock** + - 是一个显式的锁类,如可中断的锁等待、定时锁等待、公平锁选项等 + - 使用`lock()`和`unlock()`方法来获取和释放锁。 + - 公平锁按照线程请求锁的顺序来分配锁,保证了锁分配的公平性,但可能增加锁的等待时间。 + - 非公平锁不保证锁分配的顺序,可以减少锁的竞争,提高性能,但可能造成某些线程的饥饿。 +- **读写锁**(ReadWriteLock) + - 允许多个读取者同时访问共享资源,但只允许一个写入者。 + - 读写锁通常用于读取远多于写入的情况,以提高并发性。 +- **乐观&悲观锁** + - 乐观锁 **通常不锁定资源,而是在更新数据时检查数据是否已被其他线程修改。** + - 使用版本号或时间戳来实现。 + - 悲观锁 **通常指在访问数据前就锁定资源,假设最坏的情况** --》即数据很可能被其他线程修改 + - `synchronized`和`ReentrantLock`都是悲观锁的例子 +- **自旋锁** + - 锁机制 + - 线程在等待锁的时候 会循环检查锁是否可用 而不是放弃CPU并阻塞 + - 通常可以使用CAS来实现 + - 这在锁等待时间很短的情况下可以提高性能,但过度自旋会浪费CPU资源。 + + + +## CountDownLatch 是做什么的讲一讲 + + 并发包中的一个同步工具类,**用于让一个或多个线程等待其他线程完成操作后再继续执行**。 + +本质就是一个计数器 然后 + +- **初始化计数器**:创建 `CountDownLatch` 时指定一个初始计数值(如 `N`)。 +- **等待线程阻塞**:调用 `await()` 的线程会被阻塞,直到计数器变为 0。 +- **任务完成通知**:其他线程完成任务后调用 `countDown()`,使计数器减 1。 +- **唤醒等待线程**:当计数器减到 0 时,所有等待的线程会被唤醒。 + + + +## synchronized + +会在编译之后在同步的代码块前后加上**monitorenter**和**monitorexit**字节码指令 + +**monitorenter**尝试获取对象锁 对象没有被锁定或者已经获得了锁 锁的计数器+1 + +**monitorexit**指令时则会把计数器-1 + +当计数器值为0时,则锁释放,处于等待队列中的线程再继续竞争锁 + +- **主要作用**:就是实现**原子性操作**和**解决共享变量的内存可见性**问题 +- 是一种 `排他锁` 当一个线程获得锁之后其他的线程必须等待线程释放以后才能获得锁 +- 线程被阻塞或者唤醒时时会从用户态切换到内核态,这种转换非常消耗性能。 + +image-20251028220439394 + +### Reentrantlock + +`底层实现主要依赖于AQS` AQS通过内部类 Sync来实现具体的锁操作。不同的 Sync 子类实现了公平锁和非公平锁的不同逻辑 + +### 特性 + +- **可中断性 ** + - 这意味着线程在等待锁的过程中,可以被其他线程中断而提前结束等待 + - 使用了与 **LockSupport.park() **和 **LockSupport.unpark() **相关的机制来实现可中断性 +- **设置超时时间** + - 等待一定时间后如果还未获得锁,则放弃锁的获取。 + - 通过内部的 **tryAcquireNanos **方法来实现的 +- **公平锁和非公平锁** + - 默认情况下是非公平锁 也可以设置成 公平锁 +- **多个条件变量** +- **可重入性** + + + diff --git a/面试/八股文/热门200.md b/面试/八股文/热门200.md new file mode 100644 index 0000000..e69de29 diff --git a/面试/八股文/面试鸭.md b/面试/八股文/面试鸭.md new file mode 100644 index 0000000..ab15dca --- /dev/null +++ b/面试/八股文/面试鸭.md @@ -0,0 +1,1469 @@ +# Mysql + +## Mysql的索引类型有那些 + +1. ### `从数据结构` + + - **`B+树索引`** + - 适用于**范围查询** Between 和 **精确查询** in + - 支持有序数字的查 排 聚合操作 是**Mysql的默认索引** + - **`哈希索引`** + - 基于哈希表的结构 + - **不适用于范围查询 **但是适用于精确查询 & **查的非常快** + - **`倒排索引`** ->全文索引 + - **把“文档→单词”的形式变为“单词→文档”的形式** + - **`R-树索引`** ->多维空间树 + - 为空间(多维)查询准备的 + - 计算地理位置 区域查询 + +2. **```从InnoDB B+树来看```** + + - **`聚簇索引`** + - 也叫**主键索引** + - 名字由来-> 索引的叶子节点存储完整的数据行数据 -翻译->索引的结构和数据的物理存储是**深度绑定**的 —-—> 索引的叶子节点本身就是数据行的物理存储位置。 + - 拿到了主键也就拿到了 这个数据所有 + - 索引的叶子节点存储的是数据行 可以直接访问所有数据 + - 适合 范围查 &排序 + - **`非~ `** -->>二级索引 + - 仅仅和主键绑定 拿到了也只是拿到了主键和非~的 数值 想要找到其他的字段 你还要根据主键找(这一步也叫回表) + +3. **`索引的性质`** + + - **`普通索引`** + + - **非主键**&**非唯一**索引 + + - ```mysql + ALTER TABLE `table_name` ADD INDEX index_name ( `column` ) + ``` + +- **`联合索引`** + + - 多个列合在一起的普通索引 + + - 为了提高多个查询条件的性能 + + - 要按照顺序 + + - ```mysql + ALTER TABLE `table_name` ADD INDEX index_name ( `column1` ,`column2` ) + ``` + +- **`主键索引`** + + - 每一行数据都有唯一的主键 + + - 每个表只能有一个 + + - 不能为NULL + + - ```MYSQL + ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) + ``` + +- **`唯一索引`** + + - 索引中的值是唯一的 防止数据重复 + + - 可以为NULL + + - ```mysql + ALTER TABLE `table_name` ADD UNIQUE (`column`) + ``` + +- **`全文索引`** 写过了 + + - ```mysql + ALTER TABLE `table_name` ADD FULLTEXT index_name (`column`) + ``` + + + +- **`空间索引`** 通常是R-树结构 + + - ```mysql + CREATE SPATIAL INDEX idx_location ON places(location); + ``` + + + +​ + + + +### 补充 + +#### 关于倒排索引 + +我们一般搜索文章 都是通过 文章名字 ->找里面的单词 这种结构,但是如果我们想要通过文章的内容(一篇文章里面有苹果这个词)我们如何找到对应的文章???? 很简单就是**倒排索引** 这个索引将原先的 (各位可以想象成Map的KV数值)原先的存储方式是K(文章)V(苹果) 但是现在不一样了 我们改变了KV的内容 将一个K(苹果)V(包含苹果的文章1,2,3....) + +冷知识 (AI询问 正确与否代考就)未建索引时,搜索 “苹果” 需要逐篇扫描所有文章(全表扫描),时间复杂度是 **O (N)**(N 为文档总数),数据量大时会非常慢;而倒排索引通过 “关键词→文档列表” 的直接映射,查询时只需定位到关键词对应的倒排列表,时间复杂度接近 ***O (1)(定位关键词)+ O (M)(M 为匹配的文档数)***,M 通常远小于 N,因此速度会极大提升。 + +#### 为什么使用B树 + +B-树是一种**多路自平衡的搜索树** 它类似普通的平衡二叉树,不同的一点是B-树允许每个节点有更多的子节点。B-Tree 相对于 AVLTree 缩减了节点个数,使每次磁盘 I/O 取到内存的数据都发挥了作用,从而提高了查询效率。I/O渐进复杂度为O(h) + +树非常矮,通常为 3~4 层,能存放千万到上亿的排序数据。树矮意味着访问效率高,从千万或上亿数据里查询一条数据,只用 3、4 次 I/O。 + + + +## Mysql的 存储引擎有哪些?? + +1. InnoDB + - 支持事务/行级锁&外键 + - 提供包并发性能 适用于高附载的OLTP(联机事务处理)应用 + - 数据以聚集索引存储 提高检索效率 +2. MyISAM (早期的存储引擎 已逐渐被 InnoDB ) + - 不支持事物和外键 使用表级锁 + - 适合读取多 更新少 ->>数据仓库 + - 较高的读取性能 和 快的 表级锁定 +3. MEMORY + - 存在内存中 快 但是重启丢失 + - 适用于临时数据|快速缓存 +4. NDB + - 高可用性和数据分布 适合大规模分布式应用 + - 行级锁&自动分区 +5. ARCHIVE + - 适用于存储大量历史数据 支持高效的插入&压缩 + - 不支持索引 适合日志数据的存储 + + + +### 补充 + +#### 什么是聚集索引存储 为什么就提高了检索效率 + +就是聚簇索引 + + + + + + + +## 为什么用Mysql作为B+树的索引 + +1. 高效查找 + - B+树是一个AVL树 每个叶子节点到根节点的长度相同 插入、查找、删除的时间复杂度为**O(logN)** +2. 树的高度增长不快,使得磁盘的I/O次数减少 + - B+树是一个多叉树,*** 非叶子节点仅仅保存主键或索引值和页面指针***,使得每一页都能容纳更多的记录 因此内存放的索引就多 更容易命中 +3. 范围查询能力强 + - B+树适合范围查询,因为叶子节点通过**链表链接** + + + +### 扩展 + +1. B树的每个节点都存储的是完整的数据 而B+树则是存储的key&指针 完整的数据存储在叶子节点上,因此B+树可以存放更多的索引页 减少磁盘查询次数。 +2. B+树叶子组成了链表 而B树智能化每一层查找 +3. B+树查找的平均时间更加稳定 B树因为非叶子节点就保存了数据因此 返回的快慢取决于节点到根的距离 +4. 为什么不用二叉树? + - 可能会成为斜树 --> 一个链表 索引失效 +5. 为什么不用红黑树? + - 红黑树毕竟还是二叉树,一个结点点最多拥有两个直接子结点,当我们插入大量数据的时候,会导致的树的高度过高,I/O渐进复杂度为O(h)。所以还是没有有效的减少查找过程中磁盘I/O的存取次数。 + + + +## 索引的最左前缀匹配原则是什么? + +1. 索引的底层是一颗B+树,那么联合索引的底层也就是一颗B+树,只不过联合索引的B+树节点中存储的是键值。由于构建一棵B+树只能根据一个值来确定索引关系,所以数据库依赖联合索引最左的字段来构建。 +2. 只有联合索引才能谈最左前缀匹配 +3. 查询的顺序也是 按照从左到右的顺序查询 所以 + +- **原则**:联合索引必须从最左列开始匹配,且列之间连续。 +- **范围条件的影响**:范围条件会阻断后续列的索引使用。 + + + +但是 如果 + +```mysql +ALTER TABLE staffs ADD INDEX index_staffs_nameAgePos(name,age,pos); +explain select *from staffs where name='z3'and age=22 and pos='manager'; +explain select *from staffs where pos='manager' and name='z3'and age=22; +explain select *from staffs where age=22 and pos='manager' and name='z3'; +``` + +这样**三个互换了顺序** ***也会进行联合索引*** 因为最主要是因为MySQL中有查询优化器***explain,***所以sql语句中字段的顺序不需要和联合索引定义的字段顺序相同,查询优化器会判断纠正这条SQL语句以什么样的顺序执行效率高,最后才能生成真正的执行计划 + + + +**部分索引顺序** + +如果缺胳膊少腿(有最左的 但是中间的可能少了),也是按照正常的索引 +即使跳过了中间的索引,也是可以使用到索引去查询 + +但是如果只查最后的索引(没有大哥了)直接整个表的查询了 + + + +**模糊索引** + +类似模糊索引就会使用到like的语句 如果复合最左前缀的话,会使用到range或者是index的类型进行索引 + +**范围索引** + +遇到范围索引就会停止 + + + +## 三层B+树结构 + +B+树的默认数据页的大小为**16KB** + +- 每个节点页的大小为16KB +- 假设每个数据结构的主键和数据大小为1KB +- 每个内部节点 存储的是指向子节点的指针和索引键 + + + +- 第一层 根节点 指向1170个中间节点 + - 第二层 假设每个指针是6字节 +8字节的索引键(bigint)=14字节 (一个节点的大小) 那么每个中间节点可以指向1170个叶子节点 **16KB/14Byte=1170**个 +- 每个叶子节点可以存储16条数据结构 + + + + + +## 什么是回表 + +上文已经提到 由于在非聚簇索引中 索引存储的值 是索引字段的值和对应的主键的值 而并没有数据 所以当拿到这个索引的时候需要返回表中 重新去取叶子节点的数据 这就是**回表** + +``回表会带来随机IO`` 因为这个索引可能是无序的 所以查起来不好查 只能随机查询![image-20251024143700377](F:\记录\八股文\image-20251024143700377.png) + + + + + +## 索引失效 + +- 联合索引却不符合**最左前缀** +- 索引使用了计算 +- 索引上函数 +- like的随意使用 +- or的随意使用 + - 只有name有索引但是却使用了 select * from user where name="xxx" or id="xxx" +- 随意字段的使用 + - 也就是要查询的字段和匹配的字段不是一个类型 那么myslq就会做转换 **隐式字符编码转换** +- 参数不同 +- 表中两个不同的字段进行比较 + - select * form user where id>name +- 使用了ORDER BY + - order by 后面如果不是**主键** 或者 不是**联合索引 **那么就不会走索引 + +神奇的地方就是 mysql查询都是按照索引查询的 但是问题就是这个索引是否生效 (有意思) + + + +## 什么时候要建立索引 + +- 索引不是越多越好 毕竟建立索引需要空间 而且每次修改的时候还要额外去维护 +- 有大量重复的地方 不建议上索引 +- 长字段不要上索引 `but个人建议` 也是一个小tip 如果你做的是文章网站 那么好像 大概 可以给文章上倒排索引 +- 当修改频率》》》查询 还是那句话**每次修改的时候还要额外去维护** +- 通过建立联合索引 减少单个索引的建立 毕竟管理一个表 总比管理一批表合理(笑) + + + + + +## 索引越多越好? + +空间角度 + +你每次建立一个索引 就会建立一个索引表 一般来说一个索引表的大小就是16KB + +image-20251025125111136 + + + +时间角度 + +每次你写入一个数据 是不是需要在表中增加 这个插入要不要时间 ?? 你加完了 树的结构要改变 这个 为了维持B+树所作出的变形需不需要时间?? + +而且 你mysql使用索引的时候是不是需要通过评估器来评估哪个索引更好 是不是需要时间 + + + +## 如何使用explain语句进行分析 + +![image-20251025163127819](F:\记录\八股文\image-20251025163127819.png) + +- `id` 就是查询的执行顺序的标识符 数字越大优先级越高 + +- *select_type* 查询的类型 有simple primary subquery + +- table 查询的数据表 + +- type 访问的类型 比如ALL index range 等等 一般来说 性能从好到垃圾是**const > eq_ref>ref>range>index>ALL** + +- possible_keys 可能用到的索引 + + *key* `实际用到的索引` + +- key_len 索引长度 + +- ref 索引的哪一列被使用 + +- *rows* 估计要扫描的行数 数值越小越好 + +- filtered 希纳是查询条件过滤掉行的百分比 + +- *Extra* 额外信息 Using + index --》 使用覆盖索引 +where 条件过滤 +temporary 临时表 + filesort 额外的排序步骤 + + + +image-20251025163843482 + +## 如何进行mysql的优化 + +1)合理设计索引,利用联合索引进行覆盖索引的优化,避免回表的发生,减少一次查询和随机 I/O + +2)避免 SELECT *,只查询必要的字段 + +3)避免在 SQL 中进行函数计算等操作,使得无法命中索引 + +4)避免使用 % LIKE,导致全表扫描 + +5)注意联合索引需满足最左匹配原则 + +6)不要对无索引字段进行排序操作 + +7)连表查询需要注意不同字段的字符集是否一致,否则也会导致全表扫描 + +除此之外,还可以利用缓存来优化,一些变化少或者访问频繁的数据设置到缓存中,减轻数据库的压力,提升查询的效率。 + +还可以通过业务来优化,例如少展示一些不必要的字段,减少多表查询的情况,将列表查询替换成分页分批查询等等。 + + + +补充的话就是三点: 命中索引 减少IO 减少回表 + + + +## B+树查询的全过程 + +先从根节点找起 然后根据数据键与节点中的**索引值(二分)**然后找分支 + +叶子节点存储的数据行记录 但是一页有**16KB**的大小 存储的数据行不止一行 + +叶子节点中的**数据行** 利用页目录结构 利用二分 找到对应的组 + +定位后 利用链表找到对应的行 + +### + +## mysql中的count小知识 + +count(1)==count(0) 统计所有行数 **(包括null)** + +count(字段名)--》返回字段的行数 **不包括null** + + + +### char&varchar + +char **定长** 当不满的时候会用空格填满 + +varchar **变长** 需要记录额外长度 1-2字节 支持的最大长度是65535 如果值为NULL 需要一个额外的1bit进行标记 + +双路排序 select字段多 放在StringBuffer里面 进行排序后 返回给客户端 + +单路排序 select字段少 放在StringBuffer里面 + + + +## Mysql是如何实现事务的 + +- 锁 主要服务于**隔离性** + - 利用`锁的机制` 使用数据并发修改的控制 来满足事物的`隔离性` +- Redo Lock 主要服务于**持久性**,同时辅助原子性 + - 重做日志 主要就是`记录数据库的所有操作` 当mysql崩溃的时候 就重放一遍redolock 就可以恢复 +- Undo Lock回滚日志 主要服务于**原子性**,同时辅助隔离性(MVCC) + - `保存数据的历史版本` 用于事物的回滚 使得事务执行失败以后能够回到之前的样子 实现原子性 +- MVCC 多版本并发控制 主要服务于**隔离性** + - 满足了非锁定读的需求 提高并发度 实现`读已提交`和`可重复读` 两中隔离级别 实现了事务的隔离性 + +`MySQL 事务的实现是**锁、Redo Log、Undo Log、MVCC 等机制协同作用的结果**:` + +- ### 什么是事务? + + - 事务就是用户定义的一系列执行SQL语句的操作, 这些`操作要么完全地执行,要么完全地都不执行`, 它是一个不可分割的工作执行单元。 + +**事物的四大特性** + +- 原子性(Atomicity) + - 个事务中的所有操作要么全部提交成功,要么全部失败回滚 +- 一致性(Consistency) + - 数据库总是从一个一致性的状态转换到另一个一致性的状态 +- 隔离性(Isolation) + - 通常来说,一个事务所做的修改操作在提交事务之前,对于其他事务来说是不可见的。 +- 持久性(Durability) + - 一旦事务提交,则其所做的修改会永久保存到数据库。 + + + +## 什么是MVCC 多版本并发控制 + +**是一种并发控制机制** 允许多个事务`同时读取`和`写入数据` 无需等待 + +### 这么做的? + +1. 数据库为每一个事物创建一个数据快照。每当数据被修改的时候,mysql不会立刻覆盖原有的数据,而不是生成新版本的记录。每个记录都保留了对应的版本号和时间戳 +2. 多个版本串联起来形成了一条版本链 这样可以不同时刻启动的事务可以`无锁`的获得不同版本的数据。 +3. 写操作可以继续 无非就是创建新的数据版本 + + + +### 其实并不是存了很多个版本的数据 + +而是通过undolock的`保存数据的历史版本`来保留所有的版本 通过undolock来回溯到上面的版本 + +只是借助 undolog 记录每次写操作的反向操作 + + + +## Mysql的日志类型 + +### binlog 逻辑日志 二进制日志文件 + +- 用于记录mysql中的所有的DDL&DML + +- 在事务提交后产生的 所以可以用来回复数据库 +- 记录的是操作 +- 因此他可以跨平台使用 + +### redolog 物理日志 + +- 用于恢复数据 保持数据的`一致性`和`持久性` +- 而且只是 保持数据的`一致性`和`持久性` +- 记录的是数据页的修改 + +### undolog 回滚操作 + +- 作用 + - 事务回滚 + - MVCC支持 :通过版本链实现多版本的并发控制 + +image-20251027164300265 + + + + + + + +## Mysql的事务级别 + +### 读未提交 + +最低级的 + +可以读到其他事务为提交的数据 可能产生`脏读` + +### 读已提交 + +可以读取其他事务已经提交的数据 + +但是可能会产生 `不可重读 ` + +### 可重复读 + +确保数据在多个查询下的返回是一样的 + +但是可能会产生`幻读` + +mysql的默认的隔离级别 + +### 串行化 + +并发执行的SQL事务的操作 其效果与这些SQL事务按某种顺序串行执行的效果相同 + +串行执行:sql事务在开启下一个事务之前要完成全部的操作 + + + + + + + +## Mysql中有哪些锁 + +1. **行级锁** + - 仅仅对特定的`行`加锁,允许其他事务**并发`访问`不同的行**,适用于高并发场景 +2. **表级锁** + - 对整个表枷锁 其他事物**不能**对表进行任何**读写操作** 适用于保证完整性的小型表 +3. 意向锁 + - 表锁 表示某个事物对某行数据加锁的意图,分为意向共享锁和意向排他锁,主要用户行级锁的与表级锁的结合 +4. **共享锁** + - 允许事物**并发的读取同一资源** **不能修改** 智能释放锁后 才能获得锁 +5. **排他锁** + - 只允许**一个事务**对资源进行**读写** 其他只有拿到锁才可以 +6. 元数据锁 + - 用于保护数据对象的元数据 防止DDL操作时其他事务对这些对象进行修改 +7. **间隙锁** + - 针对索引中的两个记录之间的间隙枷锁 防止其他事务在间隙中插入数据---》防止幻读 +8. **临键锁** + - 行级锁+间隙锁 锁定具体的行和前面的间隙 确保在一个范围内不会出现幻读 +9. 插入意向锁 + - 等待间隙的锁 用于指示事务在某个间隙中插入记录 允许其他事务进行共享锁 但在插入时会组织其他锁 +10. 自增锁 + - 插入自增列时枷锁 保证自增的唯一性 + +## + +## Mysql事务的二阶段提交的是什么 + +为了确保**redolock binlog**之间的一致性 使用的一种机制。 + +Mysql通过二阶段提交来保证在**crash recovery** 崩溃恢复 时 不会出现**数据丢失**和**数据不一致**的情况 + +### 二阶段的两个阶段 + +- `准备阶段` 在事务提交时,Mysql的InnoDB引擎会先写入**redolog 将其状态标记为prepare**,表示事务已经准备提交但是还未真正完成 此时的redolog是预提交状态 还未标记为完成提交 +- `提交阶段` redolog标记成prepare的时候 mysql server 会写入binlog 写入成功后 mysql会通知innodb 将redolog状态改为commit 完成整个事务的提交过程 + + + +## Mysql如果发生死锁会怎么办 + +#### 自动检索与回滚 + +MySQL自带死锁检测机制 ,当检测到死锁时,数据库会自动回滚到其中一个事务,以解除死锁。通常会回滚到事务持有的资源最少的那时候。 + +### 可以手动的kill发生死锁的语句 + +可以通过命令 来手动kill它 + +```mysql +SHOW ENGINE INNODB STATUS;//展示执行的事务和事务相关的锁 + +SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;//获取事务id +SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;//获取线程id + +KILL ;//手动中止事务 + +``` + + + +## Mysql是如何解决深度分页问题 + +什么是深度分页? 数据量很大的时候,按照分页访问后面的数据。 + + + +比如 + +```mysql +`SELECT * FROM mianshiya WHERE name = 'yupi' ORDER BY id LIMIT 99999990, 10;` +``` + +这样的一条查询语句, + +可以优化成: + +```mysql +sql SELECT * FROM mianshiya +WHERE name = 'yupi' +AND id >= ( + SELECT id FROM mianshiya + WHERE name = 'yupi' + ORDER BY id + LIMIT 99999990, 1 +) +ORDER BY id LIMIT 10; +``` + + name 有索引的情况下,这样的查询直接扫描 name 的二级索引,二级索引的数据量少,且在子查询中能直接得到 id 不需要回表。将子查询得到的 id 再去主键索引查询,速度很快,数据量也小。 + + **如果直接扫描主键索引的话,数据量就比较大**,因为**主键索引包含全部的数据**。 + +当然上面的 SQL 改成 Join 也行,本质上是一样的。 + +比如 + +```mysql + select * from mianshiya + inner join + (select id from mianshiya where name = 'yupi' order by id limit 99999990,10) + as mianshiya1 on mianshiya.id = mianshiya1.id + +``` + + + +其实本质上就是先查找在排序 而不是直接写成一句话 导致一边查找一边排序 + + + +方法二 记录id + +每次分页返回当前最大的id 然后下次查询的时候 带上这个id 就可以利用id》maxid 过滤了 + +这种方式只适合 连续查询的时候 如果跳页就失效了 + + + +## 什么是mysql的主从机制?是如何实现的? + +主从机制 就是mysql的一种数据复制技术 将主数据库上面的数据同步到一个或者多个从服务器中 + + 主要是用binlog(用于记录mysql中的所有的DDL&DML ) 把主数据库的binlog放到其他的数据库中 让其他的数据库重放就行了 + +### 具体流程 + +1. 线程创立 --> 服务器开始主从机制后 会创建i/o sql线程 +2. 连接建立 -->服务器io线程与主服务器建立连接,主服务器的binlog dump线程与之交互 +3. 同步位置告知 --> 服务器的io线程 告诉主服务器的dump线程从何处开始接受binlog +4. 主服务器操作 --> 主服务器更新时 将更改的记录保存到binlog中 +5. binlog传输 --> 主服务器的dump线程检测到binlog变化 从指定的位置读取 由从服务器io线程拉取 采用 +6. 中继日志存储 --> 从服务器的io线程中 将接受的内存保存到relaylog中 +7. 数据写入 --> 从服务器的sql线程读取relaylog内容 解析成具体操作后写入自身数据表 + +image-20251030165732479 + + + +### 主从复制的类型 + +- 异步复制 主库不需要从库中相应 +- 同步复制 主库同步等待所有的库确认收到数据 +- 半同步复制 主库等待至少一个库收到数据 + + + + + +## 主从同步延迟怎么处理 + + + +首先确定一点 这个延迟啊 无法避免只能尽力减少 + +- 二次查询:如果库查不到数据 那么就去主库查一遍 但是就把压力给到主库了 有点违法主从原则了 +- 强制将写之后立马读的操作转移到主库上: 将代码写死了 比如一些写入之后立马查询的操作,绑定在一起,写死都走主库 +- 关键业务读写都走主库 : +- 使用缓存: 主库写入后同步到缓存中 这样查询时就可以先查询缓存,避免了延迟的问题 +- 提升从库配置:这没什么可解释的 金钱的力量 + + + + + +# Redis + +## Redis常见的数据结构 + +- String 最大长度是512MB + - 缓存:存session + - 计数器:统计访问量 +- Hash 底层是哈希表 + - 键值对,存储对象的属性。适合小规模数据 + - 商品详情 +- List 双向链表 + - 消息队列 + - 历史消息 +- Set 无序且不重复 用哈希表实现 + - 标签系统 + - 唯一用户集合 +- Sorted Set + - 有序集合 但是每个集合都有一个分数(score)用于排序 底层是跳表实现 + + + +## 高级的 + +- BItmap + - 用位为单位存储的数据的高效的方式 + - 用户在线 + +- HyperLongLong + - 主要用于估算基数 适合估算网站的独立的用户数量 +- GEO + - 存储地理信息的位置 +- Stream + - 日志数据结构 支持高效的信息生产和消费模式 + - 具有持久性和序列性化特性 + - 消息队列 + + + +## Redis为什么这么快 + +数据存储在内存 + +优秀的线程模型&IO模型 + +- redis采用了IO多路复用技术 +- redis采用的单线程来执行命令 无需线程的切换 避免了 上下文切换所带来的开销 + +高效的数据结构 + + + +## Redis为毛使用单线程?6.0以后又引入多线程 + +单线程的原因是因为 + +1. Redis的操作是基于内存的 其大多数操作的性能瓶颈 不是CPU导致的 +2. 使用单线程模式 减少线程上下文切换所带来的性能开销 +3. redis在单线程的情况下,使用IO多路分用模型 就可以提高redis的IO利用率 + + + +6.0使用多线程的原因是因为 + +随着数据规模的增多 请求量增多 Redis的瓶颈主要存在于网络IO,引入多线处理,可以提高网络IO处理速度 + + + +## Redis的跳表的底层原理 + +多路链表 底层保留所有的元素 每一层链表都是下一层的子集 + +image-20251106152729662 + + + +## Redis中的Hash + +是一种键值对集合 + +可以将多个字段和值存储在一个键中 + +以便于管理一些数据 + +适合存一些小数据 支持快速的增删改查 非常适合存储对象的属性 + + + +## Redis Zset的实现原理 + +是一种`跳表`+`哈希表` + +跳表 -->存储数据结构的排序和快速查找 + +哈希表 -->成员与分数的映射,提供快速查找 + +当Zset的元素过于少的时候 将使用``zip list`` 来节省内存 + +- 元素个数<128 +- 元素成员名和分值长度<64字节 + + + + + +## 如何保证redis和Mysql的数据一致性 + +1. 先更新缓存 再跟新数据库 +2. 先更新数据库 再更新缓存 +3. 删缓存 更新数据库 等后续查询数据库把数据回种到缓存 + + + +以上都不建议 + +1. 先更新数据库 再删缓存 等后续查询数据库把数据回种到缓存 +2. **缓存双删策略** 更新数据库之前先删一次缓存。更新换数据库以后 再延迟删缓存 +3. 使用**binlgo异步更新**缓存,监听到数据库的binlog的变化,通过异步的方式更新Redis缓存 + + + + + +## 击穿 穿透 雪崩 + +### 击穿 + +热点数据失效 导致大量的请求直接访问数据库 + +**解决方案**: + +1. 热点数据永不过时 -->比如双十一的时候 就可以把一些热点的关键词 给设置一个不可能过期的时间 +2. 热点数据预热 --> 预加载 +3. 动态缓存 --> 使用互斥锁,确保一个时间只能由一个请求去查询数据库查询并且更新缓存 + + + +**穿透**:查询一个不存在的数据 然后每次都查询 + +1. 分布式锁 +2. 即使是一个空的key 也存入redis中 + + + + + +**雪崩**:多个缓存数据在同一时间内失效 导致大量的请求同时访问数据库 + +1. 采用随机过期时间策略 +2. 双缓存机制 + + + +## String的底层逻辑 + +SDS结构,并结合int,embstr,raw等不同的编码实现的 + +根据长度不同编码的也不同 以44字节为节点 分embstr和raw + + + + + +## 分布式锁 + +1. set en nx命令+Lua脚本 + - 加锁&解锁 +2. 集群模式下 使用redlock + + + + + +## 实现分布式锁的问题 + +1. 业务未到期 ,锁失效 +2. 单点故障 +3. 主从不重复的问题 +4. 网络分区的问题 +5. 时钟漂移的问题 +6. 锁的可重复入的问题 +7. 误解放锁的问题 + + + + + +## Redis持久化机制 + +- RDB快照 + +通过某一时刻的数据快照来实现持久化,可以在特定时间间隔内保存数据的快照 + +适合灾难恢复和备份 能生成紧凑的二进制文件 但是可能在崩溃后丢失最后一次快照 + +- AOF日志 + +AOF通过将操作写道日志中 来实现持久化,支持将所有的写操作记下来以回复 + +文件更加准确 但是文件比较大 重写时会使用更多的资源 + + + +## 主从复制的实现原理 + +复制流程 + +- 开始同步 + - 从节点通过主节点发送PSYNC命令发起同步 + +- 全量复制 + - 如果第一次链接或者之前的连接失效,从节点请求全量复制,主节点会将当前的数据快照 发送给从节点 + +- 增量复制 + - 全量复制完成后,主从之间回保持一个长连接,然后主节点会通过这个连接 将后续的读写操作传递给从节点 + +主从架构 就是 主操作写入 从节点来读取 + + + +## 数据过期后的删除策略是什么 + +- 定期删除 + - 定期(1000ms默认)会随机检查一定数量的键,如果发现过期键 就删除 + - 主要应用在后台持续清理过期数据 +- 惰性删除 + - 在每次访问的键的时候,redis检查键是否过期,过期就删掉。这种策略保证了在使用过程中 只删除不要的数据,不访问就不删除。 + + + +## 如何解决热点key的问题 + +- 热点key的拆分 比如在key的前面加一些前缀 然后放到不同的实例上 +- 多级缓存 (CDN 本地缓存) +- 读写分离 通过主从复制 将请求分到其他的节点 +- 降级和限流 在热点key过高的时候 应该采取限流的方法 减少对于redis的请求 必要时要使用降级的数据或者空值 + + + +## 集群的实现原理是什么 + +采用hash slot 机制来分配数据 将整个空间分为16384个槽 每个redis负责一定范围的哈希槽 数据的key经过哈希计算后 分配到对应的节点 + + + +## Big key问题 + +Redis 中的 "big Key" 是指一个内存空间占用比较大的键(Key),它的危害如下: + +- 内存分布不均。在集群模式下,不同 slot 分配到不同实例中,如果大 key 都映射到一个实例,则分布不均,查询效率也会受到影响。 +- 由于 Redis 单线程执行命令,操作大 Key 时耗时较长,从而导致 Redis 出现其它命令**阻塞**的问题。 +- 大 Key 对资源的占用巨大,在进行网络 I/O 传输时,会导致获取过程中产生的**网络流量较大**,进而产生网络传输时间延长甚至网络传输阻塞的现象,例如一个 key 2MB,请求 1000 次就会产生 2000 MB 流量。 +- 客户端超时。因为操作大 Key **时耗时较长**,可能导致客户端等待超时。 + + + +### 如何解决 + +开发方面: + +- 对存储的数据进行压缩 +- 将大的key分成一些小的对象 +- 使用适合的数据结构 + +业务层面: + +- 可以根据实际情况 减少存储的内容 +- 优化业务逻辑 + +数据分布方面: + +- 采用redis集群方式 进行redis的部署 然后将大的key拆分到不同的服务器上面 + + + + + +# 设计模式 + +## 单例模式哪几种实现方式 ?如何保证线程安全 + +- 饿汉式 --> 类加载的时候就加载 + + - ```java + public class Singleton { + private static final Singleton instance = new Singleton(); + + private Singleton() {} + + public static Singleton getInstance() { + return instance; + } + } + + ``` + + + +- 懒汉式 --> 用到才创建 + + - ```java + public class Singleton { + private static Singleton instance; + + private Singleton() {} + + public static Singleton getInstance() { + if (instance == null) { + instance = new Singleton(); + } + return instance; + } + } + + ``` + +- 双重检查锁定 --> 懒汉式+ 只在第一次检查实例为空的时候加锁 + + - ```java + public class Singleton { + private static volatile Singleton instance; + + private Singleton() {} + + public static Singleton getInstance() { + if (instance == null) { + synchronized (Singleton.class) { + if (instance == null) { + instance = new Singleton(); + } + } + } + return instance; + } + } + + ``` + +- 内部静态类 --> 利用类加载机制 实现懒加载和线程安全 + + - ```java + public class Singleton { + private Singleton() {} + + private static class Holder { + private static final Singleton INSTANCE = new Singleton(); + } + + public static Singleton getInstance() { + return Holder.INSTANCE; + } + } + ``` + +- 枚举单例 --> 通过枚举实现单例 简单防止反射和序列化攻击 + +```java +public enum Singleton { + INSTANCE; + + public void bizMethod() { + // 一些业务逻辑方法 + } +} + +//使用 +Singleton singleton = Singleton.INSTANCE; +singleton.bizMethod(); + +``` + + + +## 策略模式 + +一种行为设计模式,将每种算法封装起来,让他们可以相互替换,让算法独立于使用的客户端而变化 + +### 特点 + +- 算法封装 +- 动态替换 在运行时选择和替换算法 +- 遵循开闭原则 + +### 组成 + +- 策略接口:定义算法的通用接口 +- 具体策略:实现算法的具体实现 +- 上下文类:持有策略接口的使用,调用具体策略的方法 + + + +## 模板方式 + +抽象类定义了一个算法骨架,具体的步骤由子类提供 + +- 抽象类 定义模板 +- 具体类 实现抽象方法 +- 模板方法 调用一系列步骤方法 + + + +```java +// 抽象类 +abstract class DataProcessor { + // 模板方法 + public final void process() { + readData(); + processData(); + writeData(); + } + + protected abstract void readData(); // 读取数据 + protected abstract void processData(); // 处理数据 + + protected void writeData() { // 写入数据 + System.out.println("Writing data to output."); + } +} + +// 具体实现类A +class CSVDataProcessor extends DataProcessor { + @Override + protected void readData() { + System.out.println("Reading data from CSV file."); + } + + @Override + protected void processData() { + System.out.println("Processing CSV data."); + } +} + +// 具体实现类B +class JSONDataProcessor extends DataProcessor { + @Override + protected void readData() { + System.out.println("Reading data from JSON file."); + } + + @Override + protected void processData() { + System.out.println("Processing JSON data."); + } +} + +// 客户端 +public class Main { + public static void main(String[] args) { + DataProcessor csvProcessor = new CSVDataProcessor(); + csvProcessor.process(); + + DataProcessor jsonProcessor = new JSONDataProcessor(); + jsonProcessor.process(); + } +} + +``` + + + + + +## 常见的设计模式 + +1. 单例模式 + - 保证系统中对象只有一个实例 + - 连接池 全局配置 +2. 简单工厂 + - 获取不同对象的时候可以使用 + - 将对象的创建逻辑抽离复用 +3. 策略 + - 封装一组算法让他们之间能够相互替代 能有效避免if sles + - 选择支付策略 +4. 模板 + - 提炼核心流程封装成一个模板方法 + + + + + +## 工厂模式&抽象工厂模式 + +工厂模式关注的是 **创建单一类型的对象** + +定义一个抽象方法 由子类实现具体对象的实例化 + + + +抽象工厂模式 关注的是 **创建一族相关对象 ** + +提供一个接口来创建一组相关的或者相互依赖的对象 无需指定他们的具体类 + + + + + + + +# 计网 + +## 常见的Http状态码 + +- 1XX 消息响应 + +- 2XX 成功 + +- 3XX 重定向 + +- 4XX 客户端错误 + - 403权限 +- 5XX 服务器错误 + + + + + +## HTTP 请求包含哪些内容 请求头和请求体有哪些内容 + +组成部分 + +- 请求行 + - GRT POST 之类的 + - 请求路径 + - HTTP版本 +- 请求头 + - 各种键值对 + - 客户端环境 + - 请求内容 + - 认证信息 +- 空行 + - 分割体&头 +- 请求体 + - 要发送的数据 + + + + + +## GET和POST的区别 + +GET + +- 请求数据 +- 参数通过URL拼接 直接暴露于URL中不是很安全 +- 有长度限制 2048字节 +- 幂等性 重复请求不会改变服务器的状态 + +POST + +- 提交数据 +- 参数在请求体中 +- 非幂等 + + + + + +## Http1.0 + +**无状态,无连接** :每次请求都要建立新的TCP + +**队头阻塞** :每个请求都按照顺序解决 + +**不支持持久连接**: 每次请求都要建立新的TCP 服务器消耗大 + + + +## Http2.0 + +**二进制分帧:**将http报文分割成更小的二进制,提高了传输效率,支持**多路分用** + +**头部压缩**:减少HTTP头部的大小,降低网络的开销 + +**服务器推送**: 服务器主动向 客户端发送请求 减少客户端的请求次数 + +**多路分用**:在一个TCP连接上可以同时发送多个请求,解决了HTTP1.1的对头阻塞问题 + + + +## Http3.0 + +基于QUIC协议:使用UDP协议,相当于TCP可靠性,QUIC通过自身实现可靠传输,减少了RTT + +多路分用:在一个QUIC连接上可以同时传输多个请求和相应,并支持流优先级 + +更快的连接:减少了TLS和三握手的时间 + +更少的延迟 + +image-20251109195036812 + + + +HTTP&HTTPS + +**1.数据传输安全性** + +- **HTTP**:数据以明文传输,容易被窃听、篡改。 +- **HTTPS**:通过 SSL/TLS 协议对数据进行加密传输,提供数据机密性和完整性保障。 + +2. **端口号** + +- **HTTP**:默认使用端口 80。 +- **HTTPS**:默认使用端口 443。 + +3. **性能** + +- **HTTP**:无加密过程,连接建立速度稍快。 +- **HTTPS**:基于 HTTP 上又加了 SSL或 TLS协议来实现的加密传输,加解密过程增加了计算开销,握手时间较长,但现代硬件和协议优化已使性能差距减小。 + +**4. SEO 影响** + +- **HTTP**:搜索引擎一般会降低未加密站点的排名。 +- **HTTPS**:搜索引擎更倾向于优先展示 HTTPS 网站。 + + + + + +## Tcp和Upd的区别 + +TCP + +- 可靠连接 +- 面向连接 +- 提供流量控制和拥塞控制 +- 保持数据顺序 +- 头部较大 +- 性能较低 延迟大 +- 数据传输模式 -->以字节流传输模式 +- 适用于 文件传输 web 邮件 + +UDP + +- 不可靠 +- 无连接 +- 没有流量控制和拥塞控制 +- 不保证数据顺序 +- 头部节点较小(8字节) +- 性能高 延迟小 +- 数据报传输模式 +- 实时通讯 语音 视频 游戏 + + + +## 经典TCP三报文 + +客户端首先发送一个SYN(同步序列编号)消息给服务器,服务器收到后回复一个SYN-ACK(同步序列编号-确认)消息,最后客户端再发送一个ACK(确认)消息确认服务器已经收到SYN-ACK消息,从而完成三次握手,建立起一个可靠的TCP连接。 + + + +image-20251110202708473 + +### 为什么三握手 + +- 避免历史错误连接的建立 减少双方错误的不必要的资源的消耗 +- 帮助双方同步初始化 + + + + + +## TCP是用来决解什么问题 + +可靠传输:TCP确保数据包在网络传输过程中不丢失,不重复 + +流量控制:TCP通过滑动窗口机制调节发送方的数据发送速率 ,防止因接收方的处理能力而被数据流所淹没 + +拥塞控制:TCP通过拥塞避免算法 (慢启动 拥塞避免 快速重传 快速回复) 来防止网络过载 确保网络资源的公平使用和稳定性 + +连接管理:TCP是面向连接的协议 赛用三次握手 和四次挥手 机制来管理会话,确保通信的可靠性和状态的同步 + +解决了数据不可靠的IP网络上的问题 + + + +## 四挥手 + +四次挥手的作用就是 用于安全关闭一个已经建立的连接的过程 它确保双方都能完成数据传输并安全的释放连接资源 + +### 为什么挥手需要四次? + +主要是为了确保数据完整性。 +TCP 是一个全双工协议,也就是说双方都要关闭,每一方都向对方发送 FIN 和回应 ACK。客户端发起连接断开,代表客户端没数据要发送的,但是服务端可能还有数据没有返回给客户端。就像我对你说我数据发完了,然后你回复好的你收到了。然后你对我说你数据发完了,然后我向你回复我收到了。这样才能保证数据不会丢失。 +所以一个 FIN + ACK 代表一方结束数据的传输,因此需要两对 FIN +ACK,加起来就是四次通信。 + + + +## 粘包和拆包 + +粘包:在Tcp传输中发送方的多个数据包在接收方被**合并成一个包接受**,导致多条数据粘在一起,接收方无法正确区分这些消息的边界 + +拆包:发送方的一个数据包在接受方被拆成了多个包接受,导致一个完整的消息被拆分成多个部分,接收方无法一次性接收到完整的数据 + + + +### why + +粘包:Tcp是面向字节流的协议 他不关心数据边界 + +拆包:可能由于网络传输中的MUT(最大传输单元)限制或发送缓冲区大小的限制,一个大包被拆分成了多个小包传输 + + + +### 解决: + +使用特定长度 + +添加消息分隔符 + +使用消息头 + + + +## Tcp拥塞控制的步骤 + +### ![image-20251111214414297](F:\记录\八股文\image-20251111214414297.png) + + + +## TCP/IP四层模型 + +- 应用层 + - 通过各种协议提供网络应哟个程序的功能 +- 传输层 + - 在两个主机之间提供端口到端口的通信服务 +- 网络层 + - 通过Ip协议提供数据包的路由和转发 +- 网络接口层 + - 在计算机和网络硬件之间传输数据 + + + + + +## Cookie Session Token之间的区别 + +### Cookie + +存储在用户浏览器端的一个小型数据文件,用于跟踪和保存用户的状态信息 + +用途: 保持用户登陆状态,跟踪用户行为,存储用户偏好 + +**存在客户端** + +### Session + +Session是服务器端保存用户状态的机制 每一个用户会话都会有已给唯一的SessionId + +主要用于跟踪用户在服务器上的状态信息 -> 登陆状态和购物车内容 + +**存储在服务器端** + +### Token + +**加密字符串,用于身份认证和授权**,可以包含用户信息和权限,用于验证用户身份和授权访问资源 + +认证后,后端服务会返回Token,**存储在客户端** 后续可无端访问服务端需要带上这个Token + + + +- Cookie-->客户端状态的简单存储和追踪 +- Session--> 服务器端的复杂状态管理,需要存储大量会话数据 +- Token--> 无状态的认证和授权,特别是在分布式和跨域环境下 + + + +## 输入一个网站发生了什么 + +1. 浏览器解析URL +2. DNS解析成最终的ip +3. 浏览器选择TCP/UDP +4. IP 在TCP数据包的基础上 在封装源地址IP和目标地址IP等信息 +5. MAC 通过MAC确保子网内设备两点之间的通信寻址 +6. 网卡 网卡将二进制数据转化为电信号 +7. 交换机 工作在MAC层,他会将数据包的MAC头找到另一个设备连接在交换机的哪个端口 +8. 路由器 转发 三层网络设备 包含IP层 +9. 层层验证 +10. 服务器处理 +11. 浏览器接受并且渲染 + + + + + +# 计算机组成原理 + +## 线程和进程的区别 + +进程:资源分配的基本单位 每一个进程都有一个内存空间。 + +线程:是CPU的调度的基本单位 属于进程 一个进程可以包含多个线程 线程共享进程的测村空间和资源 + + + +## 进程之间的通信方式 + +- 管道 单向通信方式 +- 命名管道 与匿名管道类似 +- 信息队列 允许进程向另一个进程发送消息 消息顺序存储 +- 共享内存 +- 信息量 +- 信号 异步通信方式 +- Socket 在网络上不同主机上的进程通信 +- 文件 通过读写文件俩来进行通信 + + + +### 调度算法 + +- 先来先服务 +- 短作业有限 +- 有限级调度 +- 时间片轮转 +- 最高相应比优先 计算影响比 +- 多级反馈队列调度 结合多个调度策略 + diff --git a/项目/ai零代码.md b/项目/ai零代码.md new file mode 100644 index 0000000..8273948 --- /dev/null +++ b/项目/ai零代码.md @@ -0,0 +1,833 @@ + + +# 后端初始化 + +## 初始化 + +springweb + +lombok + +mysqldriver + + + +把apprication.properited 改成yml格式 + +然后加入 + +```yml +spring: + application: + name: zds-ai 项目名字 + +server: + port: 2778 + servlet: + context-path: /api 后端访问的路径吧 +``` + + + +### 依赖整合 + +hutool knife4j + +```xml + + + + cn.hutool + hutool-all + 5.8.38 + + --> + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + 4.4.0 + +``` + + + + + + 改xml配置 + +```yml +# springdoc-openapi +springdoc: + group-configs: + - group: 'default' + packages-to-scan: com.zds.zdsai.controller +# knife4j +knife4j: + enable: true + setting: + language: zh_cn + +``` + + + + + +### 写模板代码 自定义异常 + +已经在包中 用就可以了 + + + + + +### 全局跨域配置(样板代码) + +直接在config包中 样板代码 + +```java +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + // 覆盖所有请求 + registry.addMapping("/**") + // 允许发送 Cookie + .allowCredentials(true) + // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突) + .allowedOriginPatterns("*") + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") + .allowedHeaders("*") + .exposedHeaders("*"); + } +} + +``` + + + + + +# 前端初始化 + +emm + +使用nvm 来管理node.js + + + +安装ant design + +```shell +npm i --save ant-design-vue@4.x +``` + +全局装配 + +```typescript +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router' + +import Antd from 'ant-design-vue' +import 'ant-design-vue/dist/reset.css' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(Antd) + +app.mount('#app') + +``` + + + +安装 + +axios + +``` +npm install axios +``` + + + +```ts +import axios from 'axios' +import { message } from 'ant-design-vue' + +// 创建 Axios 实例 +const myAxios = axios.create({ + baseURL: 'http://localhost:8123/api', + timeout: 60000, + withCredentials: true, +}) + +// 全局请求拦截器 +myAxios.interceptors.request.use( + function (config) { + // Do something before request is sent + return config + }, + function (error) { + // Do something with request error + return Promise.reject(error) + }, +) + +// 全局响应拦截器 +myAxios.interceptors.response.use( + function (response) { + const { data } = response + // 未登录 + if (data.code === 40100) { + // 不是获取用户信息的请求,并且用户目前不是已经在用户登录页面,则跳转到登录页面 + if ( + !response.request.responseURL.includes('user/get/login') && + !window.location.pathname.includes('/user/login') + ) { + message.warning('请先登录') + window.location.href = `/user/login?redirect=${window.location.href}` + } + } + return response + }, + function (error) { + // Any status codes that falls outside the range of 2xx cause this function to trigger + // Do something with response error + return Promise.reject(error) + }, +) + +export default myAxios + +``` + + + + + +## openapi 前端代码生成器 + +[@umijs/openapi - npm](https://www.npmjs.com/package/@umijs/openapi) 官网自己去学把 + +``` +npm i --save-dev @umijs/openapi + +npm i --save-dev tslib +``` + +``` +export default { + requestLibPath: "import request from '@/request'", + schemaPath: 'http://localhost:2778/api/v3/api-docs', + serversPath: './src', +} + +``` + + + +# 用户登录 + +img + + + + + +接口权限 + +1.未登录也可以使用 +2,登录用户才能使用 +3,未登录也可以使用,但是登录用户能进行更多操作(比如登录后查看全文) +4,仅管理员才能使用 + + + + + +### mybatis flex + +生成器 不用学看官方就行 + +然后就是说 这个 + +entity是数据库与实体类的连接 + + + + + +### @MapperScan + +可能扫描到mapper包 + + + +### Dto就是业务代码互相传递的类 + + + +Vo是脱敏的类 + + + +### 用户登录接口 + +```java + @Override + public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) { + //校验参数 + if (StringUtils.isAnyBlank(userAccount, userPassword)) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空"); + } + if (userAccount.length() < 4) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过知短"); + } + if (userPassword.length() < 8) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过知短"); + } + + //加密密码 + String encryptPassword = getEncryptPassword(userPassword); + + //查询用户 + + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("userAccount", userAccount); + queryWrapper.eq("userPassword", encryptPassword); + User user = this.mapper.selectOneByQuery(queryWrapper); + ThrowUtils.throwIf(user == null, ErrorCode.PARAMS_ERROR, "用户不存在或密码错误"); + //记录用户的登录态 + + request.getSession().setAttribute(USER_LOGIN_STATE, user); + return this.getLoginUserVO(user); + } +``` + +**request.getSession().setAttribute(USER_LOGIN_STATE, user);** 很重要的 种session + + + + + +## 注解(重要) + +### 0先引入依赖 + +```xml + + org.springframework.boot + spring-boot-starter-aop + + +``` + + + +### 1在annotation包下 创建注解类 + +```java +@Target(ElementType.METHOD) //在方法上的注解 +@Retention(RetentionPolicy.RUNTIME) //注解的策略 +public @interface AuthCheck { + + /** + * 必须有某个角色 + */ + String mustRole() default ""; +} + +``` + +### 2 创建一个切面 在aop包里面 + + + +```java +package com.zds.zdsai.aop; + +import com.zds.zdsai.annotation.AuthCheck; +import com.zds.zdsai.exception.BusinessException; +import com.zds.zdsai.exception.ErrorCode; +import com.zds.zdsai.model.entity.User; +import com.zds.zdsai.model.enums.UserRoleEnum; +import com.zds.zdsai.service.UserService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +@Aspect +@Component +public class AuthInterceptor { + + @Resource + private UserService userService; + + /** + * 执行拦截 + * + * @param joinPoint 切入点 + * @param authCheck 权限校验注解 + */ + //切点 -->你在什么时候拦截这个方法 + @Around("@annotation(authCheck)") + public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable { + String mustRole = authCheck.mustRole(); + RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); + // 当前登录用户 + User loginUser = userService.getLoginUser(request); + UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole); + // 不需要权限,放行 + if (mustRoleEnum == null) { + return joinPoint.proceed(); + } + // 以下为:必须有该权限才通过 + // 获取当前用户具有的权限 + UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole()); + // 没有权限,拒绝 + if (userRoleEnum == null) { + throw new BusinessException(ErrorCode.NO_AUTH_ERROR); + } + // 要求必须有管理员权限,但用户没有管理员权限,拒绝 + if (UserRoleEnum.ADMIN.equals(mustRoleEnum) && !UserRoleEnum.ADMIN.equals(userRoleEnum)) { + throw new BusinessException(ErrorCode.NO_AUTH_ERROR); + } + // 通过权限校验,放行 + return joinPoint.proceed(); + } +} + +``` + + + + + +**@Aspect**来定义这是一个切面 + +**@annotation(authcheck)** --》就是通知 只有在有authcheck注解的 才能进行权限校验 + +**joinPoint.proceed()**; 放行 + + + + + +## 前端id与后端id传值不一致 + +因为后端的int值太tmd大 而前端的js的不支持那么大的 所以会少那么一些 + +加个样板代码 + +```java +/** + * Spring MVC Json 配置 + */ +@JsonComponent +public class JsonConfig { + + /** + * 添加 Long 转 json 精度丢失的配置 + */ + @Bean + public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { + ObjectMapper objectMapper = builder.createXmlMapper(false).build(); + SimpleModule module = new SimpleModule(); + module.addSerializer(Long.class, ToStringSerializer.instance); + module.addSerializer(Long.TYPE, ToStringSerializer.instance); + objectMapper.registerModule(module); + return objectMapper; + } +} + +``` + + + + + +## 前端 + +前端想要获取用户的登陆数据 是不是每次刷新页面 就要写一个fetch函数来获取呢? + +不要 我们直接写一个引入pinna + +> pinna + +```ts +import { useLoginUserStore } from '@/stores/loginUser.ts' + +const loginUserStore = useLoginUserStore() +loginUserStore.fetchLoginUser() + +``` + +获取用户 + + + + + +# Ai大模型接入 + +## langchain4j + +> 引入依赖 + +```xml + + dev.langchain4j + langchain4j + 1.1.0 + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.1.0-beta7 + + +``` + + + +> application.xml + +```yml +# AI +langchain4j: + open-ai: + chat-model: + base-url: https://api.deepseek.com + api-key: + model-name: deepseek-chat + log-requests: true + log-responses: true + +``` + + + +### 创建接口AiCodeGeneratorService + +```java +package com.zds.zdsai.ai; + +import dev.langchain4j.service.SystemMessage; + +/** + * AI代码生成服务 + */ +public interface AiCodeGeneratorService { + + /** + * 生成HTML代码 + * + * @param userMessage 用户输入 + * @return 代码 + */ + @SystemMessage(fromResource = "prompt/codegen-html-system-prompt.txt") + String generateCode(String userMessage); + + /** + * 生成多文件代码 + * + * @param userMessage 用户输入 + * @return 代码 + */ + @SystemMessage(fromResource = "prompt/codegen-multi-file-system-prompt.txt") + String generateMultiFileCode(String userMessage); +} + +``` + +写提示词 当然 如果词的长度少 你可以不用建立txt + + + +然后就是 写一个代理工厂 来创建实例 + +```java +package com.zds.zdsai.ai;/* + *@auther 郑笃实 + *@version 1.0 + * + */ + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.service.AiServices; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Bean; + +//Ai服务创建工厂 +public class AiCodeGeneratorServiceFactory { + + //指定使用的大模型 + @Resource + private ChatModel chatModel; + + /** + * 创建AI 代码生成器代码服务 + * @return + */ + @Bean + public AiCodeGeneratorService createAiCodeGeneratorService() { + return AiServices.create(AiCodeGeneratorService.class, chatModel); + } +} + +``` + + + + + +是这样的 所以及就获得了一个String的 返回结果 + +但是问题来了你该如何将String给用户看??直接看??也行 或许 + +我们可以将String转化为JSON 让ai按照格式生成相应key 这样我们就可以 更好的展示相关的内容了 + + + +```java +package com.zds.zdsai.ai.model; + +import lombok.Data; +//Html代码结果 +@Data +public class HtmlCodeResult { + + /** + * Html代码 + */ + private String htmlCode; + + //描述 + private String description; +} + +``` + +![image-20251111194720859](F:\记录\项目\image-20251111194720859-1762861641318-1.png) + +然后改一下接口的返回值 这样就好了 + +- method: POST +- url: https://api.deepseek.com/chat/completions +- headers: [Authorization: Beare...c6], [User-Agent: langchain4j-openai], [Content-Type: application/json] +- body: { + "model" : "deepseek-chat", + "messages" : [ { + "role" : "system", + "content" : "你是一位资深的 Web 前端开发专家,精通 HTML、CSS 和原生 JavaScript。你擅长构建响应式、美观且代码整洁的单页面网站。\r\n\r\n你的任务是根据用户提供的网站描述,生成一个完整、独立的单页面网站。你需要一步步思考,并最终将所有代码整合到一个 HTML 文件中。\r\n\r\n约束:\r\n1. 技术栈: 只能使用 HTML、CSS 和原生 JavaScript。\r\n2. 禁止外部依赖: 绝对不允许使用任何外部 CSS 框架、JS 库或字体库。所有功能必须用原生代码实现。\r\n3. 独立文件: 必须将所有的 CSS 代码都内联在 `` 标签的 `