测试文档:博客初体验
本文最后更新于:1 个月前
测试文档
2024 年 10 月 3 日
这篇文章确实发挥了一点作用呵,有用没用的内容都能往这里搁。
看起来我的博客需要这么一个垃圾桶。
这是最初的博客测试文章,用来简单测试撰写功能
今天重定义这篇文章:(2023/10/01 早)
这是一篇测试文档,旨在通过实践和优化,探索和熟悉 Typora 工具的各种使用技巧和功能。
通过编写和修改这篇文档,并不断尝试工具中的不同功能和选项,我们可以更好地理解 Typora 的强大之处,并运用它提供的方式来提高写作效率和舒适度。
在 Typora 中创建流程图
使用 Mermaid 语言:Mermaid 是一种简单易懂的文本描述语言,可以用来绘制流程图、序列图、甘特图等。你可以在 Typora 中使用 Mermaid 语言来创建流程图。以下是一个简单的示例:
graph LR
A[开始] --> B[中间步骤]
B --> C[结束]
子图(Subgraphs):使用子图可以将图表分组,并在子图中创建更详细的流程或子流程。例如:
graph LR
subgraph GroupA
A1 --> A2
A1 --> A3
end
subgraph GroupB
B1 --> B2
B1 --> B3
end
A2 --> B2
A3 --> B3
样式调整:Mermaid 允许你调整图表的样式,包括节点颜色、箭头样式、背景颜色等等。通过在代码中添加样式设置,可以使你的图表更具视觉吸引力。例如:
graph LR
style A fill:#88CCEE,stroke:#FFFFFF,stroke-width:2px
style B fill:#EE8866,stroke:#FFFFFF,stroke-width:2px
style C fill:#FFDD44,stroke:#FFFFFF,stroke-width:2px
A --> B
B --> C
C --> A
时序图(Sequence Diagram):除了流程图,Mermaid 还支持绘制时序图。时序图是用于展示对象之间消息传递顺序的图表。以下是一个简单的时序图示例:
sequenceDiagram
A->>B: 请求数据
B->>C: 获取数据
C->>B: 返回数据
B->>A: 显示数据
引用
这是一个简单的引用
当我们在博文中,引用了其他站点内的文章,可以在此说明
当我们在博文中引用其他站点内的文章时,需要按照学术规范进行引用并提供正确的引用格式。引用是一种重要的学术行为,可以展示对先前研究和观点的尊重,并且为读者提供参考来源以深入了解相关主题。在引用他人文章时,应遵循以下几点原则进行扩写和优化:
- 明确标注引用内容:在引用时,必须明确标示出被引用文章的作者、标题、出处、日期等信息。这样可以确保引用内容的准确性,并避免对原作者的不当侵犯。
- 使用适当的引用格式:根据引用风格指南(如 APA、MLA 等),将引用内容格式化为正确的引用格式。引用格式通常包括作者姓名、文章标题、出版日期、出版机构、链接等细节。
- 添加适当的引用标记:在引文中添加适当的引用标记,例如引号或斜体字,以区分引用内容和自己的原创内容。
- 提供引用页脚或参考文献:在博文的末尾或适当位置,列出引用的文献的详细信息。这样读者就可以根据提供的信息找到原文进行进一步阅读。
Carbon 效果测试
- 这个效果看起来好奇怪(2023/11/13 早)
1 |
|
写给未来的一封信
2024 年 5 月 1 日
时光邮局 - 给未来的自己写一封信 (hi2future.com)
你好!这封信是我特意写给你的。
当你看到这封来信,说明它已经历经九个月的岁月年华,最终交付到了你的手中。
二零一四年秋,我第一次离家来到三官庙小学上学,那一年咱俩都是十二岁,上六年级。尽管六(1)班跟六(二)班的教室仅有一墙之隔,
你有过别人给你写过信的经历吗,应该是没有的,当然我也没有过。在这个物欲横流的社会中,人与人之间的交流愈发方便却略显麻木。
最近还在为某些即将到来却又不得不面对的琐事感到焦虑吗?印象中咱俩就这个话题也面对面聊过很多次了。二零二三年三月十七号晚,咱俩第一次在餐厅里坐着吃饭聊天。这一聊就是三个多小时,从六点半唠到了晚上快十点。我近段时间开始喜欢上了阅读和写作,只是想在这尘世之间留下我生活过的证据,或者仅仅是为了在闲暇时刻打发时间。偶尔我也会打打游戏或者刷刷短视频,在简单快乐的低趣味消磨时光。但在更多的时间里,我会选择在歌单里找一首钟爱的音乐,在富有节奏的律动中开始写作。此刻可以说我的耳边是嘈杂的或者吵闹的,但我的内心平静如水。
大家都希望过能够长久地跟自己信任的人呆在一起,期盼着他们会在自己最需要陪伴的时候,呆在我们身边。这种微不足道的陪伴,有时却往往是我们能够坚持继续生活下去的动力。他们可以是自己的亲人,也可以是亲密无间的同学或朋友。指尖触摸着热乎的手机屏幕,发送出一条条热情的消息,却不会让冰冷的现实变得更加温热。
话到嘴边却难出口,情到深处是孤独。
还有三个多月就要毕业了,我们的大学生涯也在逐渐步入尾声。今天是三月一号,这个时间节点确实没有代表着特别的意义。不过我特意查去了下日历,知道今天是二月初二。在这个普通的周六晚间,其实早在五一长假期间,我就已经基本完成了这封信的写作,但我却选择把它在六月一号这天寄出。为什么呢?也许是无心之举,想让时间冲刷淡忘这片记忆,让它在我无感知的情况下寄出可能是最好的。当然也有可能仅仅为了凑个“九”而已,谁又会知道呢。
不过这些都已经不重要了。
祝你生活愉快!
公众号
上古神话 - 饕餮
饕餮,是中国古代神话传说中的一种凶恶贪食的野兽,也是四大凶兽之一。其外貌特征十分独特且引人注目。
饕餮的形状如羊身人面,但其目在腋下,这样的设计使得它的外貌更加狰狞和神秘。它的牙齿像虎牙一样尖锐,爪子也像虎爪一样锋利。饕餮的嘴巴略弯曲内勾,仿佛随时准备吞噬一切。
饕餮的身躯庞大,据说有数十丈长,而它的头颅居然占了整个身躯的一半。同时,饕餮发出的声音如婴儿般,这种声音与其凶猛的外貌形成了鲜明的对比,使得它更加神秘和不可预测。
在性格上,饕餮的贪食程度令人震惊。它具有巨大的食欲,能够吞噬任何东西,包括人类、动物和物体。饕餮无止境地追求食物,从而引发了破坏和混乱。尽管饕餮带有恶意的形象,但它也被视为一种对抗邪恶的力量。
饕餮的外貌十分醒目,它的头部硕大,占据了整个身体的大部分比例。眼睛炯炯有神,仿佛能洞察一切,但眼中却透露着凶恶与贪婪。嘴巴张开时,尖锐的牙齿仿佛能够咬碎一切阻碍它满足食欲的障碍。
饕餮不仅外形凶猛,其性格也极为贪婪。它对食物的欲望几乎达到了疯狂的程度,无论是人类、动物还是其他生物,只要被饕餮发现,都会成为它的猎物。
总的来说,饕餮是中国古代神话中的一个重要角色,其独特的外貌和性格使其成为贪欲和暴力的象征。饕餮的形象和象征意义在古代文化中扮演了重要的角色,警示人们远离贪欲和暴力的诱惑。
上古神话 - 梼杌
梼杌(TaoWu):在《神异经·西荒经》的记载中,梼杌是西方荒原上的一头神秘而凶恶的异兽。
它的体型硕大无朋,远超过普通的老虎,仿佛一座移动的小山。梼杌的毛发长而浓密,如同黑色的绸缎,闪烁着幽暗的光泽。
这些毛发不仅为它提供了保护,还让它在夜晚的荒原中显得更为神秘莫测。其身躯健壮,肌肉虬结,充满了无尽的力量。
它的面部呈现出一种近似人类的特征,但眼神却冷酷无情,透露出凶恶和残忍。梼杌的脚爪如同虎爪一般锐利,能够轻易撕裂猎物。
它的獠牙长而尖锐,闪烁着寒光,是其在战斗中的致命武器。最引人注目的是它那异常长的尾巴,不仅用于保持平衡,还能够在战斗中发挥巨大的作用,如同一条巨大的鞭子,抽打之间能够造成毁灭性的伤害。
梼杌在荒原上肆意行凶作乱,它的出现总是伴随着血与火的灾难。它残忍无情,以猎杀其他生灵为乐,无论是凶猛的野兽还是弱小的生物,都无法逃脱它的魔爪。
它的存在,让人们感到无尽的恐惧和绝望。在荒原上,梼杌的传说被广为流传,成为了人们心中无法磨灭的阴影。
梼杌不仅是一头凶恶的异兽,更是凶恶的象征。
上古神话 - 穷奇
穷奇,这只《山海经》中记载的古老怪兽,它的形象深深烙印在每一个听闻其传说的人心中。其外形犹如一只体型巨大的老虎,但更为引人注目的是,它的背部生长着一对宽阔的翅膀。
这对翅膀强健有力,羽毛呈现出深邃的黑色,闪烁着金属般的光泽,使得穷奇能够在广阔的天空中自由翱翔,成为真正的空中霸主。
穷奇的形象在各种传说中存在着细微的差异,但无一不强调其凶猛和邪恶的特性。它的眼睛深邃而冷酷,仿佛能洞察人心最深处的黑暗。
獠牙尖锐而锋利,闪烁着寒光,仿佛随时准备撕咬猎物。它的爪子犹如钢铁般坚硬,能够轻易撕裂任何阻碍。
穷奇不仅外形恐怖,更有着独特的性格。它只听取恶人的甜言蜜语,对于好话则充耳不闻。在穷奇的眼中,善良和正义都是无用的,只有邪恶和贪婪才是它追求的真理。
穷奇的行动毫无规律可循,它时而隐匿在深山老林之中,时而出现在繁华的市井之间。每当它出现时,都会带来一片恐慌和血腥。它的翅膀遮天蔽日,獠牙和利爪闪烁着寒光,令所有生物都感到恐惧和不安。
穷奇成为了恶行的代表,它的存在让人们感到无尽的恐惧和绝望。它的传说被广为流传,成为了人们心中无法磨灭的阴影。在穷奇面前,所有的善良和正义都显得如此脆弱和无力,只有无尽的恐惧和绝望才是人们最真实的感受。
上古神话 - 蛊雕
蛊雕,一只神秘莫测的异兽,其外形融合了雕的优雅与未知的恐怖。
它的身形如同展翅高飞的雕,但头部却生长着一对异常尖锐且弯曲的双角,这对角闪烁着幽暗的光芒,仿佛能够刺破一切阻碍,赋予蛊雕一种与生俱来的威严与力量。
蛊雕的叫声独特而诡异,宛如婴儿的啼哭,初听之下纯真无邪,但仔细品味,却能感受到其中蕴含的深深恶意与无尽贪婪。每当这诡异的啼哭声响起,周围的生物都会不由自主地感到一股寒意,仿佛死神的阴影正在悄然逼近。
蛊雕的栖息地是深邃而广袤的雷泽,那里的水域为它提供了丰富的食物来源。然而,蛊雕并不满足于在水域中称王称霸,它时常展翅高飞,飞越云层,来到古时的黎云荒原狩猎人类。
但每过十年,它就会从沉睡中苏醒,开始一场疯狂的狩猎。当它醒来之际,荒原上的人类将会面临一场灾难,无数生命将在它的利爪和獠牙下消逝。这种恐怖的习性让蛊雕成为了人类心中的噩梦,每当它苏醒的年份临近,都会引发一片恐慌和不安。
更为奇特的是,蛊雕有一个与众不同的习性。它常年处于沉睡之中,仿佛在与世隔绝的梦境中度过漫长的岁月。
白日射金阙,虎豹九关开
在茂密的丛林深处,一只凶猛残暴的老虎巨兽静静潜伏。
它的身躯犹如一座移动的山峦,肌肉线条在月光下显得异常坚硬而有力,仿佛是由最坚硬的钢铁锻造而成。
那金黄色的皮毛,在夜色中闪烁着幽暗的光芒,仿佛每一根毛发都蕴含着无尽的野性和力量。
上古神话 - 凤凰
凤凰,这传说中的神鸟,以其优雅的身姿和绚丽的羽毛,在人们心中留下了深刻的印记。
它似乎从古老的画卷中跃然而出,身披五彩斑斓的羽毛,每一片都散发着淡淡的光华,宛如天边初升的朝霞,又似深海中闪烁的珍珠。
凤凰的头部高昂,一双晶莹的眼眸仿佛能洞察世间万物,深邃而神秘。它的喙如弯月,闪烁着金属般的光泽,透出无尽的威严与力量。颈部细长而优雅,轻轻摆动间,似乎在诉说着千年的故事。
它的身体矫健而有力,每一次振翅,都仿佛能掀起一阵风暴。翅膀上的羽毛层层叠叠,宛如一幅精致的画卷,色彩绚烂而又不失和谐。在阳光的照耀下,这些羽毛闪烁着耀眼的光芒,仿佛能照亮整个世界。
凤凰不仅仅是一种神鸟,更是一种精神的象征。它代表着吉祥、和谐与美好,是人们心中永远的向往和追求。
每当人们看到凤凰的身影,都会感到一种莫名的激动和敬仰,仿佛被它的美丽和力量所震撼。
如神似魔,麒麟现世
麒麟,作为中国古代神话传说中的瑞兽,其形象独特且富有深厚的文化内涵。麒麟是以鹿类的特征为主,同时融合了龙、牛、马的成分而形成的一种神秘生物。
从外部形状上看,麒麟集多种动物特征于一身。它的头部类似于龙头,但更显得温和而庄重;身躯则如鹿身,矫健而优雅;眼睛炯炯有神,如同狮眼般锐利;全身覆盖着龙鳞,闪烁着金属般的光泽;腿部则有着马蹄的矫健和力量;尾部则如同牛尾,长而有力,挥动间仿佛能扫尽一切邪恶。
麒麟在中国古代文化中有着极高的地位。它被视为吉祥瑞兽,代表着吉祥、和平、繁荣和美好。据古籍记载,只有当世上有着大善之人的存在时,麒麟才会出现。
因此,麒麟的出现往往预示着天下太平、五谷丰登。同时,麒麟也被赋予了很高的德行,它不践踏任何生物,以露水和天上掉下来的食物为生,性情温和而善良。
总的来说,麒麟作为中国古代神话传说中的瑞兽,其形象独特、文化内涵丰富。它代表着吉祥、和平、繁荣和美好,是中国传统文化中不可或缺的一部分。
深居俯夹城
1、深居俯夹城,春去夏犹清
2、晴日暖风生麦气,绿阴幽草胜花时
3、连雨不知春去,一晴方觉夏深
4、小荷才露尖尖角,早有蜻蜓立上头
5、首夏犹清和,芳草亦未歇
雾柳暗时云度月
1、柳外轻雷池上雨,雨声滴碎荷声
2、人皆苦炎热,我爱夏日长
3、云尽月如练,水凉风似秋
4、小扇引微凉,悠悠夏日长
5、雾柳暗时云度月,露荷翻处水流萤
日出江花红胜火
1、日出江花红胜火,春来江水绿如蓝
2、太清上初日,春水送孤舟
3、一轮顷刻上天衢,逐退群星与残月
4、日照香炉生紫烟,遥看瀑布挂前川
5、人言落日是天涯,望极天涯不见家
废稿
2024 年 6 月 10 日
1 |
|
1 |
|
友链
2024 年 7 月 16 日
1 |
|
吐槽
2024 年 8 月 13 日
昨天下午心情差了极点,咆哮着写下这段文字:
1 |
|
投递
2024 年 8 月 20 日
每次投递简历,总要一遍遍复制粘贴我的项目和实习经历介绍,真是太麻烦了,我直接粘贴在这里:
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
回忆录
2024 年 1 月 6 日
这些记忆真的很零散,每件小事都可以聊很多的。这里快速罗列一下“我的回忆清单”:
童年
家
学校
西彻
来胡家小卖部,摔炮,擦炮,啥都有卖
理发,我妈就是天生的理发师,一把好手
过年放炮、听戏,大学校的戏台子,贴对联,一家人大扫除,里里外外都是过年新气象,拿炭火垒小火堆,吃瓜子水果看春晚,除夕晚上打王者,好热闹!
八架山和睦村,学前班的生活,仅仅生活了一年,却感觉很漫长,经历的事情也很多:放电影,开学第一天,小偷
呐,八架山转回来之后还得适应,邓家洼小学是这辈子唯一的净土,太多欢乐的事情了
邓家洼小学,学校集体活动:院子里背书、除草、拉木炭柴火,搞防震演练,站队,王老师讲话
王老师很有意思,自己家不动手,让我们打扫,哈哈哈
很喜欢冬日的清晨,天短夜长
过六一,编排节目,姥姥门前唱大戏,很快乐,老师们都很用心,三关庙表演,完了还在饭店里吃了顿好的。教室旁边的小屋里有个电视,我俩跳得好,当排头。
最喜欢在教室里打卡、玩飞行棋了,对每个老师都有深刻印象,王老师,毛毛,邓老师,张金烂,辛艳梅,李平安
平时基本没有考试,有时候老师们组织期中考试,数学很差劲,期末考试就去
看云识天气,星期五的天气永远是最好的,外学校的同学们也都回来了,下课就能直接跑回去玩电脑了
周末总是很欢乐的,在家里玩电脑,出去跳皮筋,打卡,拉几个好朋友在村里面闲逛
说到周末,就不得不提一嘴假期了,可以玩的有很多,放假啦!当然还有假期作业啊,“二十篇日记”
侠盗猎车手-罪恶都市,最喜欢玩的游戏,植物大战僵尸,大鱼吃小鱼,忍者神龟。红警,我的世界,轴心与同盟,使命召唤
小时候没啥游戏,电脑自带的植物大战僵尸,每周都盼着哥哥回来下载新的游戏:流星蝴蝶剑、孤胆枪手、侠盗飞车
爱看的电视节目也很多,金鹰卡通,少儿频道,中央十台的法律讲堂、一线、有几部剧很深刻,过年,香包什么死在我怀里
喜欢玩小昆虫,蚂蚁,蜘蛛,荧光小屁虫赛跑,抓蜗牛
给王老师擦洗摩托、换窗户贴纸、抽水
早上上课去的早,王老师没起床,站在门外等他倒尿开门。经常看见建宏跟死人一样早读。
喜欢折纸
教材,英才教程,确实一部好教材,就是光研究里面的生字读写了。还有俩本学校发的教材,王老师卖给我们。新华字典。
人生中第一次体测,很不适应,没把我们跑死,下去测身高体重,作仰卧起坐
学校以前还有个水房来着,那边以前还是个教师,龙龙他妈在里边烧火做饭,后来关掉了。旁边是个办公室,老师换了好几个了,六一那会儿是真的快乐,那家伙在里面换衣服脱得精光。
唱歌,新来的老师,亲爱的战士你不要想家,不要想妈妈~
西彻,秘密基地,打草打一天
那会矿上要求规程,爸爸就搬个小凳子小方桌在西彻路灯下写,他说凉快
说到路灯,还记得刚修路灯那会儿,全村到处都是工人,上下学路上都能在路边捡几个螺丝钉和漂亮的小零件
磁铁,U 型磁铁和条形磁铁,当然磁铁都是偷来的,碰碰撞撞打断好几个,我还记得用飞行器换回来两个条形磁铁的壮举
偷东西,那家伙喜欢偷东西,随手拿橡皮被张老师逮住,拿了我两把尺子,一块橡皮
我家院子,那几棵树,厕所还换了两次位置,院里砌了墙,最后也没有安上大门,哈哈
后院里种庄稼,韭菜,西红柿,葱啥都有,桃树、杏树
当然收庄稼也很有趣,黄豆都是要借台机子放在西彻,一晚上开工,稻穗是要摊开来在路上或者西彻,拿摩托碾过来碾过去
门外的油柏马路,那条狗子踩下的脚印,那段时间都不能走大路的
提到狗子,又得聊聊龙龙家的那条虎子了,母狗,一胎能生十来二十个,一个都活不下来,很有意思
最喜欢下雨打雷天了,夏天的记忆最深刻了,太阳大的吓人,热死了,下雨又很凉爽,当然还有冰雹
冬天也很有趣,我是一只来自北方的狼,那片瓷砖也有点来头,上面做过很多游戏
拍视频,兄弟俩拍了很多视频。
在村里瞎逛:村头的小学,村里最下边沟里
夏天在外面开灶,洗衣服,污水就顺着那道沟渠流出大门,流到街上了,晚上摆个桌子就在院子里吃饭了,蚊子多
爱好很多,折纸,橡皮泥,飞行棋,用自己手画的地图玩,打卡,放大镜烧蚂蚁,当然还有玩泥巴,抓小蜜蜂
秋天有啥好玩的呢?打枣子
喜欢拍视频,拿个诺基亚就能拍,说到手机,我家也换过很多部手机了,每部都能讲讲,那几部破手机可是能玩 MC 的啊
闯过很多祸,很顽皮呵,上屋顶,纵火,还老喜欢拉裤子
受过很多伤,拿刀子划拉自己,坐摩托不专心,脚后跟塞后轮里被搅烂
我家开小卖铺啦,有机会就偷偷吃点小零食,每周还得去进货,爸妈不在家就去奶奶家
会做饭也是种本事,有了不去奶奶家的接口
奶奶家很温馨啊,印象中在那里过夜很多次,吃奶奶给做的饭,好几次起寺院吃汤水都在这里,那会人还很多,晚上还踩过稻穗。总奶奶家秘密很多,电视节目没啥意思,一百多个台,一般不能看,爷爷喜欢看戏,打仗,我那时候不喜欢
很晕车,但每次出门都让坐车
你们为什么属羊呢?我奶奶在我小时候捏了一只羊,从此我就属羊了,你们为什么属羊呢?
最害怕的东西,毛擦擦,夏夜里很凉快,毛擦擦也多
大哥十二岁生日那几天,玩的很开心
邓家洼最后的记忆就是王家坡开学前一晚,在后院烧小火堆
走出邓家洼后的记忆就没那么新鲜了,不过还是有些事情值得回忆,镇上饭馆吃饭,坐三轮回家
这是我今天早上的清单,后面会逐步补充,随着时间的推移,那些深埋于内心深处的记忆都能被挖掘出来
2024 年 1 月 29 日
拉裤子里,印象中上厕所不知道往厕所跑,经常拉裤子里
2024 年 3 月 9 日
对于这个话题,要讲起来是很费力的。我从小在这里长大,从幼儿园到小学到初中再到高中,这里承载了我太多太多的回忆。那过去的二十年岁月中经历过的人和事,是绝不可能用寥寥数语就能言说的。
现在,虽然我对儿时的邓家洼村仅存的概念日渐模糊,但往日的回忆却也慢慢浮现于心头,且愈发清晰和强烈了。随着年岁的增长,我愈发怀念小时候的欢快时光,更迫切地想把这些故事写下来,那是属于我的童年的故事。那么,从什么时候开始,我对童年的记忆变得模糊了呢?显而易见,在搬离村里定居到成家庄镇旁的大肚皮小区之后,几乎就在那一瞬间,我的人生仿佛被劈裂为两个阶段。原来那个在村里天真烂漫、无忧无虑戏水玩泥巴的我突然逃掉了。那个呆在村子里仿佛永远也长不大的我,逃到了一个永远也不会被找到的地方,无影无踪了。
在那个平凡的星期六的下午,我们哥俩跟往常一样,换好鞋子背上书包,关了灯锁了门,从家里出发走过大街皮,坐上我妈的小摩托去到镇上坐成班车,去到燎原大厦前坐上 1 路公交直达四中坡底。我们住在村里,要去县城上高中很麻烦,每次假期结束返校都是走这样的流程,跟过去一年多里的岁月一样;我们也才在读高二,学习上还没有抓的那么紧,在外读书一周最多两周就能回来一次,跟过去五年多里的岁月一样;今天下午去了教室得赶紧补补作业,坚持一周把这该死的学业磨完就能回家了。等晚上天快黑了回到黑乎乎的院子里,还没开门就又能闻到从厨房里飘来的妈妈做饭的清香了。在吃饱喝足后换洗衣服,听着洗衣机“轰隆隆”的运作声,就又能上炕钻进被窝里热乎乎地打游戏了,跟过去十几年里的岁月是一样的。
二零一九年十一月五号下午,我去柳林县城里读高二,那年我十七岁。
十七岁那年,我的童年结束了。
也许有用
2024 年 9 月 23 日
WebSocket 实操
理解 WebSocket 的工作流程对于搞清楚代码中的逻辑是非常关键的。WebSocket 是一种全双工通信协议,允许客户端和服务器之间在单个 TCP 连接上进行双向数据传输。它的一个显著特点是,连接一旦建立,双方可以随时互相发送数据,无需每次发送数据都重新建立连接。
在你的代码中,WebSocket
相关的工作流程是通过继承 WebSocketListener
并实现其中的几个回调方法来完成的。我们逐个解释这些方法,帮助你理清 WebSocket 的工作流程。
1. WebSocket 工作流程概览
- 连接建立:客户端发起 WebSocket 连接,服务器同意连接并确认。此时,双方可以开始发送数据。
- 消息发送/接收:客户端和服务器在连接建立后可以互相发送消息。
- 连接关闭:客户端或服务器可以随时主动关闭连接,或由于错误等原因导致连接断开。
在你的代码里,几个关键的回调函数实现了这些步骤:
2. onOpen
- 连接建立后
1 |
|
- 触发时机:当 WebSocket 连接成功建立时,服务器确认了连接,客户端和服务器可以开始发送/接收数据。
- 作用:
onOpen
方法被调用后,程序开始通过webSocket
向服务器发送请求。- 这里创建了一个新的线程
MyThread
来执行发送请求的任务。这个线程持有当前的WebSocket
连接,随后会发送请求数据给服务器。 - 通过这个设计,你可以在连接打开后马上发送请求,而不需要等待额外的用户操作。
- 这里创建了一个新的线程
3. onMessage
- 收到服务器消息
1 |
|
- 触发时机:当服务器向客户端发送消息时,
onMessage
回调被触发。 - 作用:
解析服务器的返回:服务器返回的消息通过 WebSocket 传递给客户端,消息以字符串
text
的形式返回。代码中使用Gson
库将text
解析为JsonParse
对象,这是服务器的响应内容。处理消息内容:提取出服务器返回的文本内容(
textList
),并输出到控制台。大模型的回复会被保存到totalAnswer
中,逐步构建一个完整的回答。结束对话:当
status == 2
时,表示服务器已经返回了完整的结果,此时程序可以关闭连接。历史记录的处理:程序检查是否可以加入新的对话历史(通过
canAddHistory()
),如果历史对话超过设定的长度限制,就会移除最早的几条对话。然后保存最新的大模型回答。
4. onFailure
- 连接失败
1 |
|
- 触发时机:当连接由于某种原因失败(例如网络问题、服务器故障)时,
onFailure
被调用。 - 作用:
- 处理连接失败的场景,比如服务器没有正确响应或者发生异常错误。
response.code()
返回了 HTTP 状态码,101
是正常的 WebSocket 握手响应。如果状态码不是101
,则表示连接出现了问题,并打印相关错误信息。- 出现失败时,程序会调用
System.exit(0)
终止运行。
5. onClose
- 连接关闭(未直接实现)
虽然代码中没有实现 onClose
,但 WebSocket 提供了 onClose
方法来处理连接关闭的逻辑。这个方法通常在连接被客户端或服务器主动关闭时触发,或者在连接空闲超时后自动触发。
例如:
1 |
|
6. MyThread
- 发送消息线程
1 |
|
- 作用:
MyThread
是一个辅助类,用于发送数据。它将用户的输入问题和对话历史封装成 JSON 格式,发送到服务器。- 发送完请求后,线程会进入一个循环,不断检查
wsCloseFlag
是否为true
,表示服务器已经完成返回并关闭连接。
7. WebSocket 的工作流程总结
客户端请求连接:
main()
方法中,客户端发起 WebSocket 连接。服务器确认连接:
onOpen
方法被触发,连接成功后,MyThread
开始向服务器发送请求。服务器返回消息:服务器处理完请求后,
onMessage
方法会被触发,客户端接收到服务器的回答并解析、展示给用户。处理完成并关闭连接:当服务器返回结果时,程序会检查是否可以关闭连接,并在必要时通过
webSocket.close()
主动关闭连接。异常处理:如果连接失败或出现错误,
onFailure
会处理相关逻辑。
通过这几个核心回调方法,程序能够实现稳定、完整的 WebSocket 通信流程。
是的,你理解得完全正确!
这段代码实现了一个客户端,它通过 WebSocket 向服务端发送请求,并处理服务端的响应。
具体流程是:
客户端发起请求:
在main()
方法中,客户端通过OkHttpClient
建立与服务端的 WebSocket 连接。在连接成功后(onOpen
被调用),客户端通过MyThread
向服务端发送数据,通常包含用户问题及对话历史。服务端处理请求并返回响应:
服务器收到客户端的请求后,会进行处理,生成回应内容(如大模型的回答),然后通过 WebSocket 通道发送回客户端。客户端处理服务端响应:
服务端发回消息后,客户端的onMessage
方法会被触发,接收到服务端的回应。客户端解析服务端返回的消息(如大模型的文本回答),输出给用户,并存储到对话历史中。处理完毕后,客户端关闭连接:
当服务端表示对话结束时,客户端根据状态(如status == 2
),关闭 WebSocket 连接。
你可以这样理解:
- 客户端负责:发起请求、发送数据、处理服务端响应、关闭连接。
- 服务端负责:处理客户端请求、生成响应并通过 WebSocket 返回给客户端。
这是一种典型的客户端-服务器模式,WebSocket 用于在客户端和服务器之间保持一个长连接,使得双方可以高效地双向传输数据。
要用 WebSocket 实现一个简单的聊天室功能,核心思路是通过 WebSocket 连接来实现多个客户端之间的实时消息传递。WebSocket 提供了客户端和服务器之间的双向通信,非常适合实现实时聊天场景。
实现步骤概述
1. 服务端实现:
- 服务端需要能够管理多个客户端的 WebSocket 连接,并处理消息广播。
- 服务端接收到一个客户端的消息后,将该消息发送给所有已连接的其他客户端(包括自己)。
2. 客户端实现:
- 客户端通过 WebSocket 连接到服务端,发送消息给服务端。
- 当客户端收到服务端转发的消息时,显示在自己的聊天界面中。
具体实现
我们将分别实现服务端和客户端。
1. 服务端实现(Java WebSocket Server)
使用 javax.websocket
或 Spring Boot
实现一个简单的 WebSocket 服务器。这里以 javax.websocket
实现为例。
服务端代码:
1 |
|
服务端说明:
- **
@ServerEndpoint("/chat")
**:表示 WebSocket 的访问路径是/chat
,所有连接到这个路径的客户端都会在同一个“聊天室”中。 - **
onOpen()
**:当客户端连接时,会触发该方法,服务端将新连接的Session
保存到clients
集合中。 - **
onMessage()
**:当服务端接收到某个客户端发送的消息时,触发该方法,服务端会调用broadcastMessage()
将消息广播给所有客户端。 - **
onClose()
**:当客户端断开连接时,触发该方法,移除客户端的Session
。 - **
broadcastMessage()
**:遍历所有已连接的客户端,将消息发送给它们。
启动服务:可以使用
Tomcat
或Jetty
等容器来部署这个服务端代码,或者用Spring Boot
嵌入式服务器。
2. 客户端实现(Java 客户端)
客户端使用 OkHttp
或 javax.websocket
来建立 WebSocket 连接并发送消息。
客户端代码:
使用 OkHttp
实现简单的 WebSocket 客户端:
1 |
|
客户端说明:
OkHttp
的 WebSocket 实现:这里使用OkHttp
的 WebSocket 实现来创建客户端并与服务端进行通信。- 发送消息:用户可以在控制台输入消息,消息会通过 WebSocket 发送到服务端。
- 接收消息:收到的消息会显示在控制台,
onMessage()
回调会被触发。 - 关闭连接:当用户输入
exit
时,WebSocket 连接会被关闭。
3. 客户端 HTML(使用浏览器进行聊天)
如果你想在网页上实现聊天,可以用纯 HTML 和 JavaScript 来连接 WebSocket 服务器。
HTML 和 JavaScript 客户端:
1 |
|
HTML 客户端说明:
- 通过
JavaScript
的WebSocket
API 建立连接并与服务端通信。 - 当接收到消息时,将消息显示在网页上。
- 用户可以输入消息并发送到服务端。
4. 总结
- 服务端负责管理客户端的连接,接收并广播消息。
- 客户端负责与服务端通信,发送和接收聊天消息。
- 可以通过桌面客户端(如 Java 编写的客户端)或网页客户端(HTML + JavaScript)参与聊天。
通过这种方式,你就可以实现一个简单的聊天室应用,所有客户端都可以通过 WebSocket 实现实时的双向消息通信。
完全正确!你总结得非常到位。通过 WebSocket 实现的聊天室本质上就是这样的流程:
客户端连接到服务端:每个客户端都通过 WebSocket 连接到服务器。
客户端发送消息:当客户端用户输入消息并发送时,这条消息通过 WebSocket 发送到服务端。
服务端接收并广播消息:服务端接收到消息后,会将这条消息广播给所有连接的客户端(包括发送消息的客户端),这样所有人都能实时看到。
每个客户端展示收到的消息:每个客户端收到服务端转发的消息后,显示在用户的聊天界面中。
这就是一个简单的聊天室的基本原理,其中 WebSocket 的优势就在于它能够保持长连接,允许服务端随时将消息推送给所有客户端,实现了实时的双向通信。
扩展想法
- 你可以加入用户系统,让每个用户有自己的用户名,消息显示时可以显示发送者的名字。
- 可以为消息加上时间戳,显示消息发送的具体时间。
- 加入房间功能,允许用户加入不同的聊天室房间,让不同的用户群在不同的房间内聊天。
小结:
通过这个示例,你已经掌握了 WebSocket 实现实时通信的基础。使用 WebSocket 不仅可以做聊天室,还可以用于各种实时应用,比如在线游戏、股票市场数据推送、协同编辑工具等。
这是一个很好的问题!Tomcat WebSocket 实现和Spring WebSocket 实现确实有所不同,虽然它们都依赖于 Java WebSocket API 进行基础通信,但两者的差异体现在功能、简便性以及对高级功能的支持上。
接下来,我将详细解释两者的区别,包括它们的架构、开发体验、功能扩展、适用场景等。
1. Tomcat WebSocket 实现
1.1 基础实现
Tomcat 提供了对 Java 原生 WebSocket API (javax.websocket
) 的支持。通过 Tomcat,你可以直接使用这些原生 API 来实现 WebSocket 功能。
1.2 代码实现
典型的基于 Tomcat 的 WebSocket 实现,通常使用 javax.websocket
注解和接口来定义 WebSocket 服务端点。例如:
1 |
|
1.3 优点
- 轻量级:Tomcat 的 WebSocket 实现是非常轻量的,它依赖 Java EE 标准的
javax.websocket
API,直接和 Tomcat 容器集成。没有额外的框架负担,适合那些不需要复杂功能的小型项目。 - 直接控制:你可以完全控制底层 WebSocket 连接,原生 API 提供了所有核心操作的细粒度控制。
1.4 缺点
- 扩展功能不足:Tomcat 原生的 WebSocket 支持是基础的,缺乏高级功能。比如,它没有内置的消息转发机制、没有复杂的消息处理器(如 STOMP 等协议),以及对复杂架构(如集群支持、异步任务队列等)的支持也很有限。
- 不太适合大规模应用:管理多个连接、群组消息处理和消息广播等功能需要开发者自行实现,开发复杂 WebSocket 应用可能会非常繁琐。
1.5 适用场景
- 小型应用:如果你只是需要实现简单的实时通信功能,并且不依赖复杂的 WebSocket 功能(如协议扩展或消息处理器),Tomcat 的原生 WebSocket 实现非常适合。
- 细粒度控制:对于那些希望有更多底层控制的开发者,比如直接管理连接状态、实现自定义的消息处理逻辑,Tomcat 的实现提供了非常灵活的接口。
2. Spring WebSocket 实现
2.1 基于 Spring 框架的高级实现
Spring WebSocket 是 Spring 框架基于 WebSocket 协议的一个扩展实现。它不仅封装了 Java 的原生 WebSocket API,还提供了一系列高级功能和集成支持,例如:
- 消息处理器:支持通过控制器方式(类似于 Spring MVC)处理 WebSocket 消息。
- 消息协议扩展:支持 STOMP 协议,可以处理订阅、消息广播、点对点消息等复杂场景。
- 消息转换:内置 JSON/XML 消息的转换和处理功能,结合 Spring MVC 常用的
@MessageMapping
注解,可以轻松处理不同格式的消息。
2.2 代码实现
Spring WebSocket 的实现非常类似于 Spring MVC,开发体验更加简化。例如:
1 |
|
2.3 主要功能
支持 STOMP 协议:STOMP 是基于文本的消息协议,类似于 HTTP 的请求响应模型,但为 WebSocket 通信优化了消息发送、订阅、点对点等功能。
- 通过 STOMP,客户端可以订阅主题,服务端可以向这些主题广播消息,或者发送点对点消息。
消息处理:Spring WebSocket 使用
@MessageMapping
注解来映射 WebSocket 消息,类似于 Spring MVC 中的@RequestMapping
。消息广播:通过
@SendTo
注解,你可以将处理后的消息广播给订阅了某个主题的客户端。集成 Spring Security:Spring WebSocket 支持与 Spring Security 集成,便于对 WebSocket 通信进行认证和授权。
2.4 优点
- 开发体验良好:如果你熟悉 Spring MVC,Spring WebSocket 的开发方式非常类似,使用
@MessageMapping
等注解,可以极大简化开发。 - 功能丰富:Spring WebSocket 不仅支持 WebSocket 协议,还支持 STOMP 协议扩展,实现了消息路由、广播、点对点通信等功能,适合复杂的实时通信场景。
- 集成性强:可以与整个 Spring 生态系统(Spring Boot、Spring Security、Spring Data 等)无缝集成,便于开发复杂的大规模应用。
- 异步处理:Spring WebSocket 提供异步消息处理的支持,能够更好地处理高并发下的消息接收与发送。
2.5 缺点
- 相对复杂:Spring WebSocket 比原生的 Tomcat WebSocket 更加复杂,适合更高级的开发需求。如果仅是简单的 WebSocket 通信场景,Spring 的实现可能显得“过重”。
- 依赖较多:Spring WebSocket 的功能丰富,但需要依赖 Spring 框架,这使得开发时需要引入更多的依赖库,启动时也会加载更多 Spring 相关的模块。
2.6 适用场景
- 复杂应用场景:如果你的应用需要支持消息广播、点对点通信、订阅模型、认证和授权等复杂场景,Spring WebSocket 是一个非常好的选择。
- 与 Spring 生态集成:如果你的项目已经基于 Spring 或 Spring Boot 构建,Spring WebSocket 能够无缝集成到你的项目中,极大提升开发效率和可维护性。
3. 总结与对比
特性 | Tomcat WebSocket 实现 | Spring WebSocket 实现 |
---|---|---|
底层 API | 基于 Java EE javax.websocket 原生 API |
封装了 javax.websocket ,并提供高级功能 |
消息协议支持 | 仅支持基础的 WebSocket 协议 | 支持 STOMP 等高级消息协议 |
开发复杂度 | 较低,直接使用原生 API | 较高,但类似于 Spring MVC,适合复杂场景 |
消息广播与点对点通信 | 需要自己实现 | 内置 STOMP 支持,可以轻松实现广播和点对点通信 |
异步与并发支持 | 手动处理 | 内置异步和高并发处理机制 |
集成性 | 仅依赖于 Java EE 和 Tomcat | 深度集成 Spring 生态系统,支持 Spring Boot、Spring Security |
适用场景 | 适合轻量级、简单的 WebSocket 通信 | 适合大规模、复杂的实时通信应用场景 |
消息处理方式 | 基于 @OnMessage 、Session 手动处理 |
使用 @MessageMapping 、@SendTo 等注解简化处理 |
总结:
Tomcat WebSocket 实现:
- 适合简单的实时通信场景,比如轻量的 WebSocket 聊天应用。
- 需要开发者手动处理客户端连接、消息广播、点对点通信等功能。
- 如果你希望有更多底层控制,比如手动管理连接、消息的收发,它更灵活。
Spring WebSocket 实现:
- 适合需要高级功能的场景,比如支持订阅/广播模型、身份认证、集成 Spring 生态系统的大型应用。
- 如果你熟悉 Spring MVC,Spring WebSocket 的开发体验更接近于 MVC,开发**
复杂 WebSocket 应用更加便捷**。
- 支持消息协议扩展(如 STOMP),能够轻松实现订阅模型、广播和点对点消息等功能。
选择哪种方式取决于你的项目复杂度、对实时通信功能的需求以及你对 Spring 框架的熟悉程度。如果你的项目已经使用了 Spring 框架,那么选择 Spring WebSocket 会带来更多的便利和功能扩展。
好的,下面我会分别使用 Tomcat WebSocket 实现 和 Spring WebSocket 实现 来编写一个完整的 WebSocket 服务端。两者的实现会从导入依赖、编写配置类、处理 WebSocket 消息、到运行应用的步骤进行详细讲解。
1. Tomcat WebSocket 实现
1.1 导入依赖
Tomcat WebSocket 实现依赖于 javax.websocket
API,Tomcat 容器本身已经内置支持,不需要额外导入依赖。
但是,如果你是使用 Maven
来管理依赖,可以手动引入 WebSocket API 的依赖:
1 |
|
1.2 WebSocket 配置类
基于 Tomcat 的原生 WebSocket API,不需要额外的配置类,只需在 WebSocket 端点类中通过注解配置路径即可。
1.3 WebSocket 端点实现
创建 WebSocket 端点类
1 |
|
说明:
@ServerEndpoint("/chat")
:定义了 WebSocket 的端点 URL 为/chat
。- 使用了 WebSocket 的生命周期回调函数:
@OnOpen
:当客户端连接时触发。@OnMessage
:当收到客户端消息时触发,并将消息广播给所有已连接的客户端。@OnClose
:当连接关闭时触发。@OnError
:当发生错误时触发。
1.4 部署到 Tomcat
将该 WebSocket 服务部署到 Tomcat 服务器,具体步骤如下:
创建
web.xml
文件:
如果你使用标准的Servlet
配置,确保在WEB-INF/web.xml
中配置:1
2
3<web-app>
<display-name>WebSocket Tomcat Example</display-name>
</web-app>打包项目:
使用Maven
或其他工具将项目打包成.war
文件。部署到 Tomcat:
将.war
文件放入 Tomcat 的webapps
文件夹中,启动 Tomcat。测试:
使用 WebSocket 客户端(如浏览器的开发者工具或专用的 WebSocket 测试工具)连接到ws://localhost:8080/<your-app>/chat
,发送消息并观察消息的广播效果。
2. Spring WebSocket 实现
2.1 导入依赖
使用 Spring WebSocket 的实现需要添加 Spring 的相关依赖。如果你使用 Maven
,可以使用以下依赖:
1 |
|
2.2 WebSocket 配置类
在 Spring 中,你需要创建一个配置类来启用 WebSocket 支持,并定义消息路由。
WebSocket 配置类:
1 |
|
说明:
@EnableWebSocketMessageBroker
:启用 WebSocket 消息代理支持。enableSimpleBroker("/topic")
:启用简单消息代理,使用/topic
前缀处理广播消息。setApplicationDestinationPrefixes("/app")
:定义应用的消息前缀,客户端发送到服务器的消息需要加上/app
前缀。addEndpoint("/chat-websocket")
:定义 WebSocket 的连接端点为/chat-websocket
,并支持 SockJS。
2.3 消息处理控制器
通过 Spring,WebSocket 消息的处理可以像处理 HTTP 请求一样,通过控制器来进行处理。
消息控制器:
1 |
|
说明:
@MessageMapping("/sendMessage")
:定义处理来自/app/sendMessage
的 WebSocket 消息。@SendTo("/topic/messages")
:将处理后的消息广播给订阅了/topic/messages
的客户端。
2.4 Spring Boot 主程序
如果你使用 Spring Boot,可以创建一个简单的主程序来启动应用。
1 |
|
2.5 前端代码示例
在前端,我们可以通过 WebSocket 或 SockJS 进行连接。示例使用 SockJS 和 Stomp.js 进行通信:
1 |
|
2.6 运行并测试
- 启动 Spring Boot 项目。
- 打开浏览器访问页面(如
http://localhost:8080
),发送消息时,消息会广播给所有客户端。
总结:
- Tomcat WebSocket:使用 Java 原生 WebSocket API,适合轻量级、灵活的 WebSocket 应用。
- Spring WebSocket:集成了 Spring 的特性,支持 STOMP 消息协议,适合复杂的 WebSocket 应用,如群聊、点对点消息等。
这两个方式各有优缺点,适合不同类型的应用场景。
## 二面你好!我是邓纬,我预约了周四下午14点的面试,视频会议链接目前还没有发送到我的邮箱,昨天和今天分别致电HR也没有回应,能帮我看一下吗。
如果因为系统繁忙导致视频链接没有发送至我的邮箱,烦请发送我新的视频会议面试链接;
如果是因为我这边操作有误导致错过了这次面试邀约,还请重新给我发送新的面试邀约。
如有疑问,请给我打电话:18535854762,这场面试对我很重要,谢谢了!
为什么这个人事()的电话打不通,加微信好友也没有任何回应,我只是想争取自己二面的机会。。可二面都通知我了为什么没有发视频会议链接。。
二面邀请:
我的操作是没有问题的,可会议链接到现在也没有发送:
编程之旅
2024 年 10 月 27 日
投递
2024 年 11 月 1 日