<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>leileigwl</title><description>个人博客</description><link>https://210214.xyz/</link><language>zh_CN</language><item><title>2026.04.15 工作记录｜工作流验证与美图设计室对标系统解构</title><link>https://210214.xyz/posts/2026-04-15-comfyui-mvp/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-15-comfyui-mvp/</guid><description>验证三条workflow可导入，完成美图设计室对标系统六层架构设计，编写MVP PRD明确产品边界。</description><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工作流验证&lt;/strong&gt;：通过CDP注入验证场景图链、细节图链、卖点底图链均可被ComfyUI前端完整导入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;六层架构设计&lt;/strong&gt;：完成美图设计室对标系统的完整解构——商品理解层、套图规划层、图像工作流层、模特系统、画布编排层、执行编排层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编写MVP PRD&lt;/strong&gt;：明确第一版只做单类目（T-shirt）、单平台（TikTok Shop）、单市场（EU），输出最小4图套图。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;整理执行排期表&lt;/strong&gt;：规划Day1-Day3的具体任务，把&quot;设计好解构&quot;变成&quot;可执行清单&quot;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;云端模型清单更新&lt;/strong&gt;：明确各条workflow需要的云端模型，为后续云端执行做准备。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ComfyUI本地UI能作为workflow编辑和JSON验证底座使用，问题不在&quot;能不能吃下JSON&quot;，而在&quot;怎么接到云端&quot;。&lt;/li&gt;
&lt;li&gt;美图设计室的核心不是&quot;图像生成器&quot;，而是&quot;电商设计操作系统&quot;。套图为输出单位、商品任务为输入单位、画布为最终编辑界面。&lt;/li&gt;
&lt;li&gt;MVP不是功能尽量多，而是把&quot;商品任务→套图结果&quot;这条链路先跑通。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;&quot;设计好这个解构&quot;不是画一张图，而是定义系统边界。&lt;br /&gt;
ComfyUI负责换装分割场景、Recipe负责编排执行、画布负责文案标签布局、数据层负责资产配方——边界清晰，后面才能分工开发。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结构完整，工程上可继续扩展。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;下一步计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;开始云端执行编排，把workflow体系接到云端模型。&lt;/li&gt;
&lt;li&gt;做recipe→workflow的执行映射。&lt;/li&gt;
&lt;li&gt;定义云端目录、模型位置、输入输出约定。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2026.04.14 工作记录｜上线、定时采集与备份闭环</title><link>https://210214.xyz/posts/2026-04-14-trendradar/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-14-trendradar/</guid><description>完成 TrendRadar 线上部署、定时策略调整、GitHub 提交与双重备份，形成可回滚闭环。</description><pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;完成代码上线：同步核心文件到服务器并重启容器生效。&lt;/li&gt;
&lt;li&gt;清理页面文案：移除“由 AI 自动分析生成 · TrendRadar”。&lt;/li&gt;
&lt;li&gt;调整定时策略：改为每天 &lt;strong&gt;05:00-11:00&lt;/strong&gt; 每小时采集一次。&lt;/li&gt;
&lt;li&gt;把改动推送到 GitHub 分支并创建 PR，避免直接改主分支。&lt;/li&gt;
&lt;li&gt;完成双重备份：远程备份分支 + 本地 bundle/tar 包。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;稳定交付靠流程，不靠记忆：上传、重启、验证、备份必须成套执行。&lt;/li&gt;
&lt;li&gt;“先走 PR 再合并”比直接改主分支更安全，尤其是线上配置频繁变动时。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;这次最有价值的不是“改了多少代码”，而是把“可上线、可回滚、可追溯”这条链路真正打通。&lt;br /&gt;
能持续跑起来的系统，才是好系统。&lt;/p&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;观察定时窗口运行质量，确认采集节奏和资源占用是否平衡。&lt;/li&gt;
&lt;li&gt;继续优化评分解释和前台展示，让结果更直观、更可执行。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2026.04.14 工作记录｜ComfyUI换装扩图技术选型与工作流蓝图</title><link>https://210214.xyz/posts/2026-04-14-comfyui-workflow/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-14-comfyui-workflow/</guid><description>完成AI换装技术选型报告、ComfyUI CDP交互测试、四条工作流蓝图设计，为电商套图系统奠定基础。</description><pubDate>Tue, 14 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;完成&lt;strong&gt;AI换装扩图技术选型报告&lt;/strong&gt;，对比CatVTON、IDM-VTON等多种方案，确定主链和备链。&lt;/li&gt;
&lt;li&gt;进行&lt;strong&gt;ComfyUI CDP交互测试&lt;/strong&gt;，通过Chrome DevTools Protocol注入JSON workflow，验证前端加载能力。&lt;/li&gt;
&lt;li&gt;设计&lt;strong&gt;四条工作流蓝图&lt;/strong&gt;：主图换装链、场景图链、细节图链、卖点底图链。&lt;/li&gt;
&lt;li&gt;编写&lt;strong&gt;云端完整试跑流程&lt;/strong&gt;和&lt;strong&gt;云端模型清单&lt;/strong&gt;，明确后续云端执行路径。&lt;/li&gt;
&lt;li&gt;整理&lt;strong&gt;诺梵提效需求提炼&lt;/strong&gt;，把业务需求翻译成技术任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ComfyUI工作流不是&quot;一张大图&quot;，而是&quot;一套体系&quot;。模块化拆分比大一统更可维护。&lt;/li&gt;
&lt;li&gt;CatVTON在服装换装场景表现稳定，适合作为主链；IDM-VTON作为备链兜底。&lt;/li&gt;
&lt;li&gt;CDP注入能真实验证&quot;前端吃下JSON workflow&quot;的结果，比静态文件检查更有说服力。&lt;/li&gt;
&lt;li&gt;云端执行要提前规划模型清单和API格式，不能等到本地调完再想云端。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;做AI产品不是&quot;先找一个万能workflow&quot;，而是&quot;先定义你的能力边界&quot;。&lt;br /&gt;
把换装、场景、细节、海报拆成四条链，每条链负责一个清晰任务，比塞进一个超级节点图更靠谱。&lt;/p&gt;
&lt;p&gt;结构清晰，后面扩展才不痛苦。&lt;/p&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;继续验证三条辅链workflow的production-ready版本。&lt;/li&gt;
&lt;li&gt;完成美图设计室对标系统的完整解构设计。&lt;/li&gt;
&lt;li&gt;编写MVP PRD，明确第一版产品只做什么。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2026.04.13 工作记录｜把推荐理由改成“老板听得懂”</title><link>https://210214.xyz/posts/2026-04-13-trendradar/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-13-trendradar/</guid><description>今天把 TrendRadar 的推荐理由从技术串改成业务口语表达，重点解决重复命中和可读性问题。</description><pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;重构了推荐理由生成逻辑，不再展示“命中/公式”式机器文案。&lt;/li&gt;
&lt;li&gt;增加去重处理，修复 &lt;code&gt;employment+employment&lt;/code&gt; 这类重复展示问题。&lt;/li&gt;
&lt;li&gt;把理由改为老板视角：为什么值得关注、为什么会买单、预期会产生什么效果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;同一套评分逻辑，如果表达方式不对，用户感知价值会大幅下降。&lt;/li&gt;
&lt;li&gt;前台“解释文案”和后台“评分明细”要分层：前台讲决策价值，后台保留依据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;真正提升产品体验的，不一定是更复杂的算法，而是更准确的表达。&lt;br /&gt;
把“可计算”翻译成“可决策”，才是 AI 产品落地的关键一步。&lt;/p&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;继续观察推荐理由在真实页面中的阅读反馈。&lt;/li&gt;
&lt;li&gt;把评分展示进一步标准化，减少用户对分值含义的理解成本。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2026.04.08</title><link>https://210214.xyz/posts/2026-04-08/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-08/</guid><description>从会话恢复到博客落地：把两天内容拆分成可发布日记</description><pubDate>Wed, 08 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;今天做的事很聚焦：先恢复上下文，再按固定模板把两天内容拆开，最后直接落到博客目录，避免“总结停留在聊天里”。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;h3&gt;1. 恢复会话与素材&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;调用 &lt;code&gt;resume-session&lt;/code&gt;，加载最近会话摘要。&lt;/li&gt;
&lt;li&gt;识别可用素材来源：昨天产出的盘点文档与今天的对话目标。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 切换到指定写作技能&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;按你的要求改用 &lt;code&gt;leileigwl-blog&lt;/code&gt; 写作路径。&lt;/li&gt;
&lt;li&gt;放弃合并叙事，改成“昨天一篇、今天一篇”的独立发布结构。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 自动定位博客目录并写入&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;自动定位到：&lt;code&gt;/Users/leileigwl/Code/leileigwl-blog/src/content/posts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;新增两篇文件：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2026-04-07.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2026-04-08.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;先恢复上下文再写，能避免偏题和信息错位。&lt;/li&gt;
&lt;li&gt;同一批素材按“时间维度拆分”，比合并成一篇更适合持续复盘。&lt;/li&gt;
&lt;li&gt;真正有效的内容生产不是“写得多”，而是“写完能直接发布”。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;把内容从“临时聊天输出”变成“项目内可检索资产”，这一步看起来小，但长期价值非常大。&lt;br /&gt;
流程越稳定，创造力越能留给真正重要的事情。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;明天计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 继续沿用这套双日记结构，保证稳定输出。&lt;/li&gt;
&lt;li&gt;[ ] 补齐封面图与标签规范，让历史文章检索更清晰。&lt;/li&gt;
&lt;li&gt;[ ] 把“恢复会话 → 写作 → 入库”做成默认日更流程。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-04-08-cover.jpg&quot; alt=&quot;封面&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2026.04.07</title><link>https://210214.xyz/posts/2026-04-07/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-07/</guid><description>把 Agent 资产从散点目录整理成可复用的项目地图</description><pubDate>Tue, 07 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;今天的核心不是“又写了几个文档”，而是把过去分散在不同目录里的 Agent 相关资产，统一成一套可查、可比、可复用的项目地图。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;h3&gt;1. 统一盘点口径，清理噪声&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;~/Code&lt;/code&gt; 范围内做 Agent / Skills 扫描。&lt;/li&gt;
&lt;li&gt;排除了依赖与构建噪声目录（如 &lt;code&gt;node_modules&lt;/code&gt;、&lt;code&gt;venv&lt;/code&gt;、&lt;code&gt;dist&lt;/code&gt;、&lt;code&gt;build&lt;/code&gt; 等），保证结果可用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 产出三份核心文档&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;code目录-agent-skill清单.md&lt;/code&gt;：给出总体统计与目录清单。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;code目录-自研agent项目清单.md&lt;/code&gt;：聚焦自研项目内可识别 Agent 目录。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;code目录-自研agent完整项目画像.md&lt;/code&gt;：按完整项目视角整理，便于展示和决策。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 提炼重点项目，形成展示优先级&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;对 OpenMOSS、AgentTavern、BossAutoAgent 等项目进行了结构化归类。&lt;/li&gt;
&lt;li&gt;给出“可截图/可讲解”的优先级序列，降低后续分享与复盘的组织成本。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;目录扫描只是起点，真正有价值的是可决策信息（技术栈、入口、项目形态、可展示性）。&lt;/li&gt;
&lt;li&gt;“完整项目画像”与“命中清单”必须分离，才能兼顾全量检索与重点输出。&lt;/li&gt;
&lt;li&gt;先统一口径再做自动化，后续每次增量盘点都会更稳、更快。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;以前我总把“知道东西在哪”当成进展，今天意识到真正的进展是：&lt;br /&gt;
&lt;strong&gt;把信息组织成下一步可以直接行动的结构。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;明天计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 把今天的盘点结果转成可持续更新模板（固定字段 + 固定输出格式）。&lt;/li&gt;
&lt;li&gt;[ ] 基于重点项目补一版深挖笔记（架构、关键模块、可复用点）。&lt;/li&gt;
&lt;li&gt;[ ] 将盘点结果接入日更博客流程，形成“做事即沉淀”的闭环。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-04-07-cover.jpg&quot; alt=&quot;封面&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2026.04.03</title><link>https://210214.xyz/posts/2026-04-03/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-03/</guid><description>把 Boss 投递链路从“状态成功”推进到“真实消息发送成功”的一天</description><pubDate>Fri, 03 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;今天的核心任务只有一件：
&lt;strong&gt;把 Boss 直聘自动投递从“显示已沟通”修到“真的发出打招呼文本”。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我不是在做表面状态，而是在补真实业务闭环：投递成功 -&amp;gt; 进入沟通 -&amp;gt; 消息送达。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;h3&gt;1. 先把问题跑实，确认不是错觉&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;用 CDP 连接真实 Chrome 会话，逐步复现“已投递但没发招呼”的场景。&lt;/li&gt;
&lt;li&gt;验证到关键事实：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;friend/add&lt;/code&gt; 接口成功不等于首条文本消息成功；&lt;/li&gt;
&lt;li&gt;页面会出现简历相关弹层，导致聊天输入链路被阻断；&lt;/li&gt;
&lt;li&gt;UI 能显示“正在沟通”，但不代表首条招呼语已送达。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 对照 Boss-Aide，确认正确实现路径&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;对比 &lt;code&gt;Boss-Aide&lt;/code&gt; 项目后确认：
&lt;ul&gt;
&lt;li&gt;它是“投递接口 + 聊天发送链路”两段式；&lt;/li&gt;
&lt;li&gt;首条消息走 websocket/chat 协议发送，不只靠 &lt;code&gt;friend/add&lt;/code&gt; 参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;这个对照直接明确了修复方向，避免在错误接口上继续试错。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 在 boss-ai-helper 里补齐真实发送链&lt;/h3&gt;
&lt;p&gt;今天落地了三个关键改造：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新增“待发送招呼语队列”：
&lt;ul&gt;
&lt;li&gt;投递成功后把消息先入队，防止丢消息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;新增聊天页 websocket 发送器：
&lt;ul&gt;
&lt;li&gt;在 chat 页面用站内发送通道发真实文本，而不是只改状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;新增后台自动拉起聊天页：
&lt;ul&gt;
&lt;li&gt;让队列可以被消费，不再卡在职位页。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同时把岗位分析的关键信息（如 bossName）继续透传，提升消息目标匹配精度。&lt;/p&gt;
&lt;h3&gt;4. 处理工程侧问题并完成构建验证&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;增加 &lt;code&gt;protobufjs&lt;/code&gt; 依赖用于发送封包。&lt;/li&gt;
&lt;li&gt;完成两轮构建验证，产物正常输出。&lt;/li&gt;
&lt;li&gt;保持现有功能不回退，重点保证“首条招呼真实送达”这条主链。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;自动化最容易“看起来成功”&lt;/strong&gt;
只有把“状态变化”和“真实副作用（消息送达）”分开验证，才算完成闭环。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对照成熟实现能大幅缩短排障路径&lt;/strong&gt;
与其盲猜接口参数，不如直接找已验证方案做结构对齐。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;复杂流程必须引入队列思维&lt;/strong&gt;
页面跳转、弹层阻断、异步时序都可能导致消息丢失；有队列才能稳。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;今天最重要的不是“修了一个 bug”，而是把标准再次拉齐：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;业务自动化必须以真实结果为准，不以 UI 显示为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这条标准以后会继续沿用到所有“看似成功”的场景里。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 用真实投递批次做回归，验证不同公司/岗位下的首条消息成功率。&lt;/li&gt;
&lt;li&gt;[ ] 给发送链路加更细的埋点（入队、出队、发送成功、失败原因）。&lt;/li&gt;
&lt;li&gt;[ ] 增加失败重试策略分级，区分“目标未就绪”和“通道不可用”。&lt;/li&gt;
&lt;li&gt;[ ] 梳理一份自动投递可靠性清单，固化为后续开发标准。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;一句话总结&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;今天把自动投递从“状态正确”推进到了“结果正确”：真正把打招呼文本发出去了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-04-03-cover.jpg&quot; alt=&quot;封面&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2026.04.02</title><link>https://210214.xyz/posts/2026-04-02/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-04-02/</guid><description>从技能体系到项目交付：把“记录-执行-复盘-发布”跑成闭环的一天</description><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;今天不是只做了 CutX，而是把我整套 AI 工作流又往前推进了一步：
从「skills 管理」到「浏览器联网能力验证」，再到「视频裁剪系统重构、仓库重建、规则沉淀、博客发布」。
核心目标很明确：&lt;strong&gt;让系统更懂我，并且每次都能直接产出可用结果。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;h3&gt;1. 技能体系与记忆机制梳理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;检索和导出本机 skills，确认当前可用能力边界。&lt;/li&gt;
&lt;li&gt;明确了「记录」和「推送」两类触发动作的优先级与用途：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;记录&lt;/code&gt;：沉淀偏好与规则，让模型持续贴合工作方式。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;推送&lt;/code&gt;：把当日结果通过 Bark 输出成可读总结。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;重点推动“跨 session 学习”思路，不只依赖当前上下文，要求能结合历史会话持续进化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 联网与浏览器能力验证（web-access / dev-browser）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;反复验证了浏览器连接与可见操作链路，确保不是“口头调用”，而是真实可执行。&lt;/li&gt;
&lt;li&gt;在多个站点场景下测试了检索、跳转、内容提取与故障重试，补齐了“连得上但看不到结果”的断点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. CutX 项目重构与全流程实跑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;重新定义核心剪辑原则：
&lt;ul&gt;
&lt;li&gt;用「重来」做分割信号；&lt;/li&gt;
&lt;li&gt;全局判断，不做段位硬编码；&lt;/li&gt;
&lt;li&gt;重复表达保留后面的正确版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;反复用原视频 + SRT 对比回归，针对误删/漏删/重复保留问题做多轮规则修正。&lt;/li&gt;
&lt;li&gt;连续输出并复核 &lt;code&gt;final.srt&lt;/code&gt;、&lt;code&gt;final_cut.mp4&lt;/code&gt;、&lt;code&gt;decision_report.md&lt;/code&gt;，直到关键错误被消掉。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. GitHub 仓库重建与清理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;远端仓库清理后，重建私有仓库并重新连接本地 &lt;code&gt;cutx&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;完成首推后，按“只保留代码”原则做二次清理：
&lt;ul&gt;
&lt;li&gt;移除 draft 产物、音视频文件、缓存文件；&lt;/li&gt;
&lt;li&gt;更新 &lt;code&gt;.gitignore&lt;/code&gt;，防止后续再把产物推上去。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. Skill 指向修正&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;发现本机 &lt;code&gt;cutx&lt;/code&gt; skill 仍指向旧路径（历史工程），已切换到当前项目路径与当前运行方式，避免后续调用跑偏。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;“能跑通”不等于“可交付”&lt;/strong&gt;
指标过关（例如 near-dup=0）并不代表语义上没有问题，最终必须回到逐句业务判断。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;硬编码最容易在边界场景翻车&lt;/strong&gt;
一旦按“尾段/中段”这种位置假设做判断，遇到新语料就会错；全局规则 + 可解释决策才更稳。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;仓库治理是产品体验的一部分&lt;/strong&gt;
产物文件、缓存文件混进仓库，会直接拉低协作效率；“代码仓库”和“运行产物”必须分层。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;记忆机制要服务执行，而不是增加负担&lt;/strong&gt;
记录不是为了堆文档，而是为了下一次执行更快、更准、更少反复。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;今天最有价值的一点是：
我不是在“修一个脚本”，而是在训练一套长期可复用的个人工作系统。&lt;/p&gt;
&lt;p&gt;当我把标准说清楚（比如“重来分割 + 后者优先 + 不硬编码”），
系统就能逐步从“会执行”变成“会按我的判断方式执行”。&lt;/p&gt;
&lt;p&gt;这才是我真正要的 AI 协作状态。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;明天计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 把 CutX 所有阈值参数外置到配置文件，减少代码内硬编码。&lt;/li&gt;
&lt;li&gt;[ ] 增加一套自动回归样例（固定视频片段 + 期望 SRT）做快速验收。&lt;/li&gt;
&lt;li&gt;[ ] 把“记录 + 推送 + 博客发布”做成每日固定闭环，减少人工整理成本。&lt;/li&gt;
&lt;li&gt;[ ] 继续优化技能调用前置判断，让常用 skill 在高频场景下更稳定触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;一句话总结&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;今天把“技能系统、视频自动剪辑、仓库治理、知识沉淀”串成了一条闭环：从能做，到稳定可复用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-04-02-cover.jpg&quot; alt=&quot;封面&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2026.03.31</title><link>https://210214.xyz/posts/2026-03-31/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-03-31/</guid><description>为 wewrite 公众号自动创作系统优化核心功能</description><pubDate>Tue, 31 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;为 wewrite 公众号自动创作系统添加了&lt;strong&gt;文章强制检查功能&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;新增 &lt;code&gt;check_and_add_personal_impact()&lt;/code&gt; 函数，确保文章包含&quot;对你意味着什么&quot;部分&lt;/li&gt;
&lt;li&gt;缺失时自动补充约200字的个人影响内容，使用第二人称写作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;重构了 &lt;code&gt;ai_call()&lt;/code&gt; 函数，添加 &lt;strong&gt;API 重试机制&lt;/strong&gt;（最多重试2次，间隔10秒）&lt;/li&gt;
&lt;li&gt;尝试将 wewrite 写作规范整合到 prompt 生成流程中&lt;/li&gt;
&lt;li&gt;Git commit: &lt;code&gt;feat(wewrite): 添加文章强制检查与API重试机制&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;公众号文章质量可以通过&quot;后处理强制检查&quot;机制保障，在 parse() 后插入校验逻辑&lt;/li&gt;
&lt;li&gt;API 调用稳定性问题可以通过简单的重试机制解决，无需引入复杂的队列库&lt;/li&gt;
&lt;li&gt;写作规范整合需要考虑 prompt 长度限制，分段读取文件内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;做自动化系统时，&lt;strong&gt;质量保障&lt;/strong&gt;比单纯追求效率更重要&lt;/li&gt;
&lt;li&gt;重试机制看似简单，但能解决大部分生产环境的不稳定问题&lt;/li&gt;
&lt;li&gt;AI 生成的文章缺少&quot;个人视角&quot;是普遍问题，强制补充能显著提升读者价值&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;验证强制检查功能在生产环境的效果&lt;/li&gt;
&lt;li&gt;测试 API 重试机制的实际稳定性&lt;/li&gt;
&lt;li&gt;继续优化 wewrite 的其他模块&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03-31-cover.jpg&quot; alt=&quot;配图&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2026.03.30</title><link>https://210214.xyz/posts/2026-03-30/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-03-30/</guid><description>完成 CDP 客户端开发和 Boss 插件测试，推进浏览器自动化工具链建设</description><pubDate>Mon, 30 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;开发了 &lt;strong&gt;CDP (Chrome DevTools Protocol) Python 客户端&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现 WebSocket 连接到 Chrome DevTools Protocol&lt;/li&gt;
&lt;li&gt;支持页面获取、连接、命令发送等核心功能&lt;/li&gt;
&lt;li&gt;绕过 MCP 依赖，直接操作 Chrome 浏览器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成 &lt;strong&gt;Boss 插件测试&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多轮测试截图验证（boss_extension_test.png, boss_success.png, boss_fixed.png 等）&lt;/li&gt;
&lt;li&gt;测试流程顺利，无明显错误&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;strong&gt;wewrite 项目&lt;/strong&gt;开发自动创作脚本&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto_create.py&lt;/code&gt; - 自动创作脚本 v1&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auto_create_v2.py&lt;/code&gt; - 改进版本 v2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CDP 协议&lt;/strong&gt;：可以直接通过 WebSocket 操作 Chrome，适合自动化测试场景&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试验证习惯&lt;/strong&gt;：多轮截图记录测试结果，按阶段命名便于回溯&lt;/li&gt;
&lt;li&gt;流程：&lt;code&gt;get_pages → connect → send_command → 截图验证&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;浏览器自动化工具链正在逐步完善。CDP 方案比依赖 MCP 更直接可控，测试截图命名规范让问题追溯更高效。&lt;/p&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] 将 auto_create_v2.py 提交到 wewrite 项目&lt;/li&gt;
&lt;li&gt;[ ] 完善 CDP 客户端的错误处理&lt;/li&gt;
&lt;li&gt;[ ] 整理测试截图并归档&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2026.03.28</title><link>https://210214.xyz/posts/2026-03-28/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-03-28/</guid><description>Claude Code 自学习系统搭建、视频后期工具迭代、X/Twitter 信息监控</description><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;h3&gt;1. Claude Code 自学习系统搭建&lt;/h3&gt;
&lt;p&gt;花了大半天时间，给 Claude Code 设计并实现了一套&lt;strong&gt;偏好自学习系统&lt;/strong&gt;。核心思路很简单——AI 应该越用越懂你，而不是每次从零开始。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;架构设计：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分层存储&lt;/strong&gt;：按「商业 / 模型建构 / 项目开发 / 通用」四个分类存储偏好&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发词机制&lt;/strong&gt;：说&quot;记录&quot;就自动扫描全部上下文（包括被 compact 压缩的历史 session 日志），提取思维模式和工作习惯&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动纠正检测&lt;/strong&gt;：当用户纠正 AI 时，自动记录到 corrections.md，同一错误出现 3 次以上才升级为永久规则&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按需加载&lt;/strong&gt;：每次会话只加载 rules.md（永久规则），对话过程中根据话题动态加载对应分类的偏好文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;解决了什么问题：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;之前每次开新会话，AI 都不记得我的习惯。现在通过读取 JSONL session 日志，即使上下文被压缩过，也能恢复完整历史。这个方案不需要改 Claude Code 本身，纯靠 SKILL.md + 偏好文件实现。&lt;/p&gt;
&lt;h3&gt;2. 视频后期工具迭代&lt;/h3&gt;
&lt;p&gt;对视频剪辑工作流进行了持续优化，经过多轮迭代，最终完成了自动化裁剪工具的定型版本。主要解决了检测精度和裁剪边界的问题，现在可以更准确地识别需要处理的片段。&lt;/p&gt;
&lt;h3&gt;3. X/Twitter 信息监控工具&lt;/h3&gt;
&lt;p&gt;搭了一个 X/Twitter 监控工具，实时追踪 Elon Musk、Sam Altman、Karpathy 的推文动态，通过 Bark 推送到手机。方便第一时间获取 AI 圈的重要动态。&lt;/p&gt;
&lt;h3&gt;4. Context7 vs GitHub MCP 工具调研&lt;/h3&gt;
&lt;p&gt;确认了 Context7 和 GitHub MCP 的能力边界：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;能力&lt;/th&gt;
&lt;th&gt;不能做&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Context7&lt;/td&gt;
&lt;td&gt;查第三方库官方文档&lt;/td&gt;
&lt;td&gt;读源码、搜仓库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub MCP&lt;/td&gt;
&lt;td&gt;搜索仓库、读源码/Issue/PR&lt;/td&gt;
&lt;td&gt;查库文档&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gh CLI&lt;/td&gt;
&lt;td&gt;搜索、操作 GitHub&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;web_reader&lt;/td&gt;
&lt;td&gt;抓任意网页内容&lt;/td&gt;
&lt;td&gt;结构化 API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;结论：要搜 GitHub 仓库找现成方案，得装 GitHub MCP，Context7 帮不了这个。&lt;/p&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Claude Code 的 session 日志完整保存在 &lt;code&gt;~/.claude/projects/&lt;/code&gt; 下的 JSONL 文件中，即使 &lt;code&gt;/compact&lt;/code&gt; 压缩了上下文，原始对话依然可恢复&lt;/li&gt;
&lt;li&gt;自学习系统不一定要靠模型微调，&lt;strong&gt;文件级的偏好存储 + 按需加载&lt;/strong&gt; 就能实现&quot;越用越懂你&quot;的效果&lt;/li&gt;
&lt;li&gt;Context7 只管库文档，GitHub 仓库搜索得用专门的 MCP&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;工具的价值在于&lt;strong&gt;自动触发&lt;/strong&gt;，不是被动调用。好的系统设计应该让用户无感知——该加载什么、该记录什么，AI 自己判断。今天的自学习系统就是这个理念的落地：用户只需要说&quot;记录&quot;，剩下的全自动。&lt;/p&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;继续完善 X 监控工具，测试 Bark 推送稳定性&lt;/li&gt;
&lt;li&gt;尝试安装 GitHub MCP，提升仓库搜索效率&lt;/li&gt;
&lt;li&gt;探索更多自动化工作流&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03-28-cover.jpg&quot; alt=&quot;封面&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2026.03.27</title><link>https://210214.xyz/posts/2026-03-27/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-03-27/</guid><description>Chrome 扩展全栈开发、Logic Skill 规范设计、1362 个 Skills 生态扫描、视频剪辑方案调研</description><pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;今天是高产的一天，完成了 5 个课题。重点产出是一个 Boss 直聘 AI 助手 Chrome 扩展，以及一套用 Prompt Engineering 替代代码逻辑的 Skill 设计规范。&lt;/p&gt;
&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;h3&gt;1. Boss AI Helper Chrome 扩展&lt;/h3&gt;
&lt;p&gt;从零开发了一个 Boss 直聘 AI 助手的 Chrome MV3 扩展，半天搞定全部核心功能：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Popup 设置页&lt;/td&gt;
&lt;td&gt;AI 模型配置（GLM/DeepSeek/OpenAI/Claude）、API Key、求职偏好&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;简历量化&lt;/td&gt;
&lt;td&gt;粘贴简历 → AI 提取技能标签和工作经历时间线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;聊天 AI 回复&lt;/td&gt;
&lt;td&gt;检测 HR 新消息 → 生成回复建议 → 一键填入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;职位匹配分析&lt;/td&gt;
&lt;td&gt;提取职位信息 → AI 评分 → 推荐打招呼话术&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;今日统计&lt;/td&gt;
&lt;td&gt;投递/回复/面试/拒绝 + 转化漏斗&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;技术栈：&lt;strong&gt;WXT + Vue 3 + TypeScript + Element Plus + Pinia + Vitest + Playwright&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;测试结果：73 个单元测试全过，6 个 E2E 测试全过，构建产物 1.42MB。&lt;/p&gt;
&lt;p&gt;最大的技术坑是 Chrome MV3 的 main-world 通信。Content script 运行在隔离世界中，无法直接访问页面 DOM 事件。解决方案是用 &lt;code&gt;window.postMessage&lt;/code&gt; 桥接 content script 和 main-world script。&lt;/p&gt;
&lt;p&gt;另外接入了 GLM 模型（通过阿里云 DashScope 端点），需要特殊处理 thinking + text 的响应格式。&lt;/p&gt;
&lt;h3&gt;2. Logic Skill 规范：用 Markdown 替代代码&lt;/h3&gt;
&lt;p&gt;花了不少时间把 DBS 商业工具箱中的设计模式提炼成通用规范。&lt;/p&gt;
&lt;p&gt;核心理念：传统方式是用 Python/JS 写逻辑代码调用 AI API，Logic Skill 方式是&lt;strong&gt;用结构化自然语言把判断逻辑写进 SKILL.md，让 AI 自己执行逻辑&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;代码写法:  if user_has_product: enter_phase(&quot;content_diagnosis&quot;)
SKILL.md:  如果用户有产品 → 进入内容诊断阶段
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;建立了&quot;代码逻辑 → 自然语言&quot;的完整映射表，总结了 6 种可复用的设计模式（路由器、消解漏斗、信号检测、多维度评分、双模式切换、条件触发），以及一套约束系统。&lt;/p&gt;
&lt;p&gt;最重要的发现：&lt;strong&gt;60% 靠正面指令，40% 靠负面约束&lt;/strong&gt;。负面约束比正面指令更重要。比如&quot;不要说&apos;每个人的情况不同&apos;&quot;比&quot;要给出具体建议&quot;更有效。&lt;/p&gt;
&lt;h3&gt;3. 1362 个 Claude Skills 生态扫描&lt;/h3&gt;
&lt;p&gt;对本地安装的全部 1362 个 Claude Code Skills 做了分类扫描，其中 251 个包含 GitHub 链接，180+ 个唯一仓库（去重后）。&lt;/p&gt;
&lt;p&gt;重点筛选了搜索/记忆/爬虫/研究四大类共 52 个 skill，发现了几个很有价值的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;deep-research&lt;/strong&gt; — 自主研究：规划→搜索→阅读→综合报告&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;skill-seekers&lt;/strong&gt; — 自动将文档网站、GitHub 仓库转为 Claude Skill&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;recallmax&lt;/strong&gt; — 持久化记忆召回系统&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hierarchical-agent-memory&lt;/strong&gt; — 分层记忆架构，减少 token 消耗&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 自动视频剪辑方案调研&lt;/h3&gt;
&lt;p&gt;为 CutX 视频剪辑工具调研&quot;自动检测口播视频中说错字段落&quot;的技术方案。&lt;/p&gt;
&lt;p&gt;推荐方案：&lt;strong&gt;ASR 转录 + 正则匹配自我纠正关键词 + 可选 LLM 辅助判断&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ASR 转录 → 合并上下文窗口 → 匹配&quot;不对/重来/我是说&quot;等关键词 → 标记裁剪区间 → ffmpeg 裁剪
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;调研了 20+ 个开源项目，WhisperX（13k stars）最适合做词级时间戳对齐，CleanTone 项目做了 Whisper + Generative AI 失语检测的完整方案。&lt;/p&gt;
&lt;h3&gt;5. Solar Config Skill&lt;/h3&gt;
&lt;p&gt;用上面总结的 Logic Skill 规范，写了一个光伏储能系统配置诊断的 Skill（360 行 SKILL.md）。四条核心公理：电压决定一切、先问需求再推设备、信息有优先级、安全是底线。这个就不展开说了。&lt;/p&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome MV3 的 main-world script 和 content script 是隔离的&lt;/strong&gt;，必须通过 &lt;code&gt;window.postMessage&lt;/code&gt; 桥接。这是 Extension 开发中很容易踩的坑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt Engineering 可以替代简单的代码逻辑&lt;/strong&gt;。if/else、状态机、循环这些结构都可以用自然语言 + 约束系统实现。关键是负面约束要写够。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GLM API 的响应格式和 OpenAI 不同&lt;/strong&gt;，有 thinking + text 两部分，需要特殊解析。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;失语检测（Disfluency Detection）&lt;/strong&gt; 是一个成熟的 NLP 子领域，有 reparandum/interregnum/repair 的标准标签体系。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;p&gt;Logic Skill 规范最有意思。以前觉得 Prompt Engineering 就是&quot;写好提示词&quot;，但现在发现它本质上是一种&lt;strong&gt;编程范式&lt;/strong&gt;——用自然语言替代代码来编排 AI 的行为。&lt;/p&gt;
&lt;p&gt;约束系统是灵魂。写正面指令告诉 AI &quot;要做什么&quot;只成功了一半，写负面约束告诉 AI &quot;绝对不要做什么&quot;才是可靠运行的关键。这跟写代码是一样的道理：正常流程 + 边界处理 + 异常处理，缺一不可。&lt;/p&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Boss AI Helper：登录 Boss 直聘实测完整功能，调优页面选择器&lt;/li&gt;
&lt;li&gt;[ ] 把 Logic Skill 规范应用到更多实际场景&lt;/li&gt;
&lt;li&gt;[ ] CutX：实现 &lt;code&gt;detect_mistakes()&lt;/code&gt; 检测器&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2026.03.26</title><link>https://210214.xyz/posts/2026-03-26/</link><guid isPermaLink="true">https://210214.xyz/posts/2026-03-26/</guid><description>剪影视频工作流、博客改造、记忆技能</description><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今天做了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;做了剪影视频工作流&lt;/li&gt;
&lt;li&gt;发了个小面包视频，差不多&lt;/li&gt;
&lt;li&gt;改了个博客&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天学到了什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;有一个记忆的skills很牛，记录了&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;今天的感悟&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;想睡觉，5点半夜才睡&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;明天的计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cutx进行实验，收集很多个模版&lt;/li&gt;
&lt;li&gt;练习说话，说话断句，找模版，做视频&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03-26.png&quot; alt=&quot;配图&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>2023 To 2024</title><link>https://210214.xyz/posts/2023-to-2024/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-to-2024/</guid><description>一年里经历了很多，收获也很多</description><pubDate>Sun, 31 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;2023 To 2024&lt;/h2&gt;
&lt;p&gt;&quot;一年里经历了很多，收获也很多。从疫情放开，从校门踏出。三月的瘦西湖、完全盛开的樱花、长江上、明城墙上等日落、泰山上看万家灯火、云龙湖上看小船、万平口玩沙子、万圣节游乐园里抓npc、操场上堆小雪人、躺瘦西湖雪地里……&quot;&lt;/p&gt;
&lt;p&gt;&quot;尝试了去主动要微信（第一次被答应的时候，超开心，一次体验都很难忘🙇‍）&quot;&lt;/p&gt;
&lt;p&gt;&quot;一直在吃吃吃路上（超级喜欢跟好友一起聚餐。火锅排第一早点都很好吃...）&quot;&lt;/p&gt;
&lt;p&gt;&quot;到处在拍，拍了很多很多照片（puq没看到就是被我私藏了哈哈&quot;&lt;/p&gt;
&lt;p&gt;&quot;真正意义上赚到了人生中第一桶金&quot;&lt;/p&gt;
&lt;p&gt;&quot;遇到眼里有我的女孩&quot;&lt;/p&gt;
&lt;p&gt;一年里，很感谢身边许多给我带来了帮助，鼓励，温暖，甜蜜，安慰。&lt;/p&gt;
&lt;p&gt;但自己也有过失、误会，冷落过、伤害过一些人，给你们留下了不好的回忆，还请包涵，历史绝不会重演。&lt;/p&gt;
&lt;p&gt;2023的一年很难就此说清，有所成长的一年·&lt;/p&gt;
&lt;p&gt;2024，新的一年，对自己有要求，对明天有所期待·&lt;/p&gt;
</content:encoded></item><item><title>2023.12.12</title><link>https://210214.xyz/posts/2023-12-12/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-12/</guid><description>今天就是双十二啦，有惊喜到的一天</description><pubDate>Tue, 12 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;今天就是双十二啦，有惊喜到的一天&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;夜晚怎么老是失眠最近，没睡好，写六级的时候在图书馆居然还睡了一会会&lt;/p&gt;
&lt;p&gt;一天里收到了好多投喂哈哈哈，给自己整不会了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;zyd生日的小蛋糕&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-12-1.png&quot; alt=&quot;蛋糕&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;来自小土豆的熊猫大福，好可爱，给我也写了六级鼓励，加油不辜负&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-12-2.png&quot; alt=&quot;熊猫大福&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;来自小伙伴的好喝的，味道不赖&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-12-3.png&quot; alt=&quot;好喝的&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ssh带来的小芭乐，重新品了一下芭乐，跟我平时吃的水果还是不一样，涩，但是收到投喂还是很开心的&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-12-4.png&quot; alt=&quot;芭乐&quot; /&gt;&lt;/p&gt;
&lt;p&gt;今天真的有很认真的在写六级哦，课是翘的差不多了，虽然只剩下是3天了，临时抱佛脚·&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-12-5.png&quot; alt=&quot;六级&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;一直拖欠的事得清掉，这都马上又周末，放寒假回家·&lt;/p&gt;
&lt;p&gt;把笔记写完早点睡觉呀，小乖，爱自己，注意身体&lt;/p&gt;
</content:encoded></item><item><title>2023.12.11</title><link>https://210214.xyz/posts/2023-12-11/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-11/</guid><description>焦虑的一天</description><pubDate>Mon, 11 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;呜呜呜，上来就是焦虑的一天&lt;/li&gt;
&lt;li&gt;摆烂改不掉，六级过不了&lt;/li&gt;
&lt;li&gt;让我看看是谁每天12.才起，晚上不睡，早上不起，难怪小猪都喜欢吃了睡睡了吃&lt;/li&gt;
&lt;li&gt;中午起来上课咯，上课啥也听不懂嘞，等着考试日期出来复习复习&lt;/li&gt;
&lt;li&gt;说好的大作业呢，18号要交，今儿都11号，还不写啊，怎么了这是，小宝宝&lt;/li&gt;
&lt;li&gt;六级只剩下 &lt;strong&gt;5Days&lt;/strong&gt;咯，这些天你能加油嘛，leilei那么多人看着你呢，咱可丢不起这脸&lt;/li&gt;
&lt;li&gt;收到了好朋友投喂的大玉米·，已经很久没吃过啦，好爱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/corn.jpg&quot; alt=&quot;玉米&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;收集了很多很多&lt;/li&gt;
&lt;li&gt;安慰人还挺累，好在我心里课代表还算心里健康，情绪稳定，给自己的性格加个鸡腿🍗
&lt;ul&gt;
&lt;li&gt;越是喜欢的人，越要远离&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;背背单词早点睡觉哦好不好，小乖&lt;/p&gt;
</content:encoded></item><item><title>2023.12.10</title><link>https://210214.xyz/posts/2023-12-10/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-10/</guid><description>日常生活记录</description><pubDate>Sun, 10 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;不到中午都起不来&lt;/li&gt;
&lt;li&gt;写写六级时间就过去&lt;/li&gt;
&lt;li&gt;软件开发文档也写好啦&lt;/li&gt;
&lt;li&gt;不过有一个大作业又被拖着了，晚期拖延&lt;/li&gt;
&lt;li&gt;今天快递到了，准备好拼一拼&lt;/li&gt;
&lt;li&gt;下雨天，哪都不想去，很冷嘟&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-10.png&quot; alt=&quot;2023.12.10&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;早睡早期身体好，明天早八肯定去&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2023.12.9</title><link>https://210214.xyz/posts/2023-12-9/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-9/</guid><description>比赛日的一天</description><pubDate>Sat, 09 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;要比赛的一天，一觉睡醒就是中午了&lt;/li&gt;
&lt;li&gt;浅浅看了知识点，唠唠嗑，看看抖音就到考试了&lt;/li&gt;
&lt;li&gt;难受哇，在宿舍比个赛都有室友阴阳。咳嗽咳嗽，吃饭bia鸡嘴，垃圾袋吹来出去，喝可乐要叹气，害，是人也知道他这故意的，受不了一点&lt;/li&gt;
&lt;li&gt;好在考试还不赖，题目也写的七七八八·&lt;/li&gt;
&lt;li&gt;比完赛就想着摆烂，vocal，跟高中一样，考完当天的晚自习就一点不想学习，打了好久游戏，卸了卸了，寒假回去再玩吧&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-9.png&quot; alt=&quot;2023.12.9&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;越发自己是小恋爱脑，烤爆！&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2023.12.8</title><link>https://210214.xyz/posts/2023-12-8/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-8/</guid><description>累人的一天</description><pubDate>Fri, 08 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;新的一天，真是累了我自己咯&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;夜里先是失眠，失眠了好久，看手机，小红书&lt;/li&gt;
&lt;li&gt;早上难得起来，困死也要上早八&lt;/li&gt;
&lt;li&gt;中午睡午觉后就出来玩啦，是开心的one day，快乐的时光过得有点快，希望时间能够停留&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-8-1.jpg&quot; alt=&quot;开心的one day&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;wok，居然又没有写六级，断掉了，真没出息，三天打🐟的小笨蛋&lt;/li&gt;
&lt;li&gt;最让我难过的事，给自己蠢一天，耳机掉厕所，怎么都想不到。好在不贵，有一只能陪我&lt;/li&gt;
&lt;li&gt;又是听喜帖街的一天，连着几天咯，一直听，喜欢的喜欢的&lt;/li&gt;
&lt;li&gt;晚上知道了好兄弟群里有人被猫挠了，一下子打了9针，手都肿了，2000块，还不能报销，想想这2000块吃啥不香，心里也为朋友难受。
&lt;ul&gt;
&lt;li&gt;警惕摸猫猫&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-8-2.png&quot; alt=&quot;警惕摸猫猫&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;晚上回来都好懒，一到宿舍就有摆烂的氛围……，笔记写完，日记写完，要过好久
&lt;ul&gt;
&lt;li&gt;拖延症到晚期了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;把今天规划一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;起床看一眼qsort排序算法&lt;/li&gt;
&lt;li&gt;睡醒考试&lt;/li&gt;
&lt;li&gt;写完人工智能报告&lt;/li&gt;
&lt;li&gt;六级六级，不能再歇了&lt;/li&gt;
&lt;li&gt;做个好梦~&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>2023.12.7</title><link>https://210214.xyz/posts/2023-12-7/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-7/</guid><description>补的笔记</description><pubDate>Thu, 07 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是一篇补的笔记，日记第二天记真的就啥都记不得，水一篇嘿嘿&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;衣服洗啦&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-7-1.jpg&quot; alt=&quot;衣服洗啦&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;日记补啦&lt;/li&gt;
&lt;li&gt;今天有看了一部动画电影：你看起来好像很好吃，被萌到啦&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-7-2.jpeg&quot; alt=&quot;你看起来好像很好吃&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;英语六级写啦，不过就是错的多多，看题太慢了，这还没上战场就要噶了&lt;/li&gt;
&lt;li&gt;睡觉好像多了一点点，摆烂的哈哈哈哈，怎么老是想摆烂啊&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>2023.12.6</title><link>https://210214.xyz/posts/2023-12-6/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-6/</guid><description>代码写完啦</description><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;今天终于把两代码写完了哦·憋死我了&lt;/p&gt;
&lt;p&gt;感冒还是没痊愈，吃了头孢，略微犯困&lt;/p&gt;
&lt;p&gt;今天收到了大螃海，还不知道怎么吃&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-6.jpg&quot; alt=&quot;大螃海&quot; /&gt;&lt;/p&gt;
&lt;p&gt;六级断掉了，还没做，明天有时间，好好写吧&lt;/p&gt;
&lt;p&gt;一旦有时间记得把新的大作业写了吧，早点结束&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;今天任务总体完成&lt;/p&gt;
</content:encoded></item><item><title>2023.12.5</title><link>https://210214.xyz/posts/2023-12-5/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-5/</guid><description>第二篇记录</description><pubDate>Tue, 05 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;第二篇记录&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;接到了一个网易图片下载的单子，但是奈何里面出现的图片使用html2canvas无法下载，到嘴的鸭子跑飞咯&lt;/li&gt;
&lt;li&gt;今天必须写完那拖的两篇代码，再不写就要给人家违约了&lt;/li&gt;
&lt;li&gt;呀，获奖啦，去年一个奖项没有，今年好容易争气了，运气也算不错，本来以为就二等奖的，开心的&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12-5.png&quot; alt=&quot;获奖&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;写了6级，正确率还不错&lt;/li&gt;
&lt;li&gt;讨厌，今天被小朋友吓到了，给我发恐怖视频&lt;/li&gt;
&lt;li&gt;马上写好今天的课堂总结睡觉&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>2023.12.4</title><link>https://210214.xyz/posts/2023-12-4/</link><guid isPermaLink="true">https://210214.xyz/posts/2023-12-4/</guid><description>日记第一篇</description><pubDate>Mon, 04 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;今天是日记第一篇&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从今天起，把自己的小博客重新搭建完成，并进行每天的日记记录，以此鞭策同时监督自己。&lt;/p&gt;
&lt;p&gt;博客内容以每日的生活，所做的事为主，主打一个记录生活。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;完成的事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;重新整理了一下博客内容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;七牛云正常使用，顺便上传张图测试一下&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://img.210214.xyz/blog/wallhaven-rrjvyq.png&quot; alt=&quot;wallhaven&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;开始顺利慢慢进入六级状态&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最后今天还需要把代码完成一下&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后去跑一跑2km&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>JavaScript加密解密模块</title><link>https://210214.xyz/posts/js-encryption/</link><guid isPermaLink="true">https://210214.xyz/posts/js-encryption/</guid><description>常见加密算法及JavaScript/Python实现</description><pubDate>Sun, 14 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;常见加密算法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对称加密（加密解密密钥相同）：DES、3DES、AES、RC4、Rabbit&lt;/li&gt;
&lt;li&gt;非对称加密（区分公钥和私钥）：RSA、DSA、ECC&lt;/li&gt;
&lt;li&gt;消息摘要算法/签名算法：MD5、SHA、HMAC、PBKDF2&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;常见编码算法：Base64&lt;/p&gt;
&lt;h3&gt;JavaScript 加密解密模块&lt;/h3&gt;
&lt;h4&gt;Crypto-JS&lt;/h4&gt;
&lt;p&gt;Crypto-JS 支持 MD5、SHA、RIPEMD-160、HMAC、PBKDF2、AES、DES、3DES（Triple DES）、Rabbit、RC4 等，&lt;strong&gt;不支持 RSA、ECC&lt;/strong&gt;，是应用比较广的加密模块，使用命令 &lt;code&gt;npm install crypto-js&lt;/code&gt; 安装。&lt;/p&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Crypto-JS 文档：&lt;a href=&quot;https://cryptojs.gitbook.io/docs/&quot;&gt;https://cryptojs.gitbook.io/docs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Crypto-JS Github：&lt;a href=&quot;https://github.com/brix/crypto-js&quot;&gt;https://github.com/brix/crypto-js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Node-RSA&lt;/h4&gt;
&lt;p&gt;Node-RSA 对 RSA 算法提供了支持，使用命令 &lt;code&gt;npm install node-rsa&lt;/code&gt; 安装。&lt;/p&gt;
&lt;p&gt;参考资料：Node-RSA Github：&lt;a href=&quot;https://github.com/rzcoder/node-rsa&quot;&gt;https://github.com/rzcoder/node-rsa&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;JSEncrypt&lt;/h4&gt;
&lt;p&gt;参考资料：JSEncrypt 对 RSA 算法提供了更加全面的支持，使用命令 &lt;code&gt;npm install jsencrypt&lt;/code&gt; 安装。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSEncrypt 文档：&lt;a href=&quot;http://travistidwell.com/jsencrypt/&quot;&gt;http://travistidwell.com/jsencrypt/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JSEncrypt Github：&lt;a href=&quot;https://github.com/travist/jsencrypt&quot;&gt;https://github.com/travist/jsencrypt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Python 加密解密库&lt;/h3&gt;
&lt;h4&gt;Cryptodome &amp;amp; Crypto&lt;/h4&gt;
&lt;p&gt;在 Python 中有很多算法是通过第三方库 Cryptodome 或者 Crypto 来实现的，Cryptodome 几乎是 Crypto 的替代品，Crypto 已经停止更新好多年了，有很多未知错误，所以&lt;strong&gt;不建议安装 Crypto ！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Cryptodome 支持几乎所有主流加密算法，包括 MD5、SHA、BLAKE2b、BLAKE2s、HMAC、PBKDF2、AES、DES、3DES（Triple DES）、ECC、RSA、RC4 等。&lt;/p&gt;
&lt;p&gt;Cryptodome 使用命令 &lt;code&gt;pip install pycryptodome&lt;/code&gt; 进行安装，Crypto 使用命令 &lt;code&gt;pip install pycrypto&lt;/code&gt; 进行安装。&lt;/p&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Crypto 库：&lt;a href=&quot;https://www.dlitz.net/software/pycrypto/&quot;&gt;https://www.dlitz.net/software/pycrypto/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cryptodome 库：&lt;a href=&quot;https://www.pycryptodome.org/en/latest/&quot;&gt;https://www.pycryptodome.org/en/latest/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Hashlib&lt;/h4&gt;
&lt;p&gt;Python 的标准库 hashlib 提供了常见的摘要算法，如 MD5，SHA、BLAKE2b、BLAKE2s 等。&lt;/p&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hashlib 库：&lt;a href=&quot;https://docs.python.org/3/library/hashlib.html&quot;&gt;https://docs.python.org/3/library/hashlib.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;廖雪峰 hashlib：&lt;a href=&quot;https://www.liaoxuefeng.com/wiki/1016959663602400/1017686752491744&quot;&gt;https://www.liaoxuefeng.com/wiki/1016959663602400/1017686752491744&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HMAC&lt;/h4&gt;
&lt;p&gt;Python 的标准库 hmac 对 HMAC 算法提供了支持。&lt;/p&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hmac 库：&lt;a href=&quot;https://docs.python.org/3/library/hmac.html&quot;&gt;https://docs.python.org/3/library/hmac.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;廖雪峰 hmac：&lt;a href=&quot;https://www.liaoxuefeng.com/wiki/1016959663602400/1183198304823296&quot;&gt;https://www.liaoxuefeng.com/wiki/1016959663602400/1183198304823296&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;pyDes&lt;/h4&gt;
&lt;p&gt;Python 的第三方库 pyDes 对 DES 算法提供了支持。使用命令 &lt;code&gt;pip install pydes&lt;/code&gt; 进行安装。&lt;/p&gt;
&lt;p&gt;参考资料：pyDes 库：&lt;a href=&quot;https://github.com/twhiteman/pyDes&quot;&gt;https://github.com/twhiteman/pyDes&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;ESA&lt;/h4&gt;
&lt;p&gt;Python 的第三方库 rsa 对 RSA 算法提供了支持。使用命令 &lt;code&gt;pip install rsa&lt;/code&gt; 进行安装。&lt;/p&gt;
&lt;p&gt;参考资料：rsa 库：&lt;a href=&quot;https://stuvel.eu/python-rsa-doc/&quot;&gt;https://stuvel.eu/python-rsa-doc/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;加密解密基本参数&lt;/h2&gt;
&lt;p&gt;在一些对称和非对称加密算法中，经常会用到以下三个参数：初始向量 iv、加密模式 mode、填充方式 padding，先介绍一下这三个参数的含义和作用：&lt;/p&gt;
&lt;h3&gt;初始向量 iv&lt;/h3&gt;
&lt;p&gt;在密码学中，初始向量（initialization vector，缩写为 iv），又称初始变数（starting variable，缩写为 sv），与密钥结合使用，作为加密数据的手段，它是一个固定长度的值，iv 的长度取决于加密方法，通常与使用的加密密钥或密码块的长度相当，一般在使用过程中会要求它是随机数或拟随机数，使用随机数产生的初始向量才能达到语义安全，让攻击者难以对原文一致且使用同一把密钥生成的密文进行破解。&lt;/p&gt;
&lt;p&gt;参考资料：维基百科：&lt;a href=&quot;https://en.wikipedia.org/wiki/Initialization_vector&quot;&gt;https://en.wikipedia.org/wiki/Initialization_vector&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;加密模式 mode&lt;/h3&gt;
&lt;p&gt;目前流行的加密和数字认证算法，都是采用块加密方式，就是将需要加密的明文分成固定大小的数据块，然后对其执行密码算法，得到密文。数据块的大小通常采用跟密钥一样的长度。加密模式在加密算法的基础上发展出来，同时也可以独立于加密算法而存在，加密模式定义了怎样通过重复利用加密算法将大于一个数据块大小的明文转化为密文，描述了加密每一数据块的过程。目前利用较多的加密模式有以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ECB：Electronic Code Book（电子码本模式）&lt;/strong&gt;，是一种基础的加密方式，密文被分割成分组长度相等的块（不足补齐），然后单独一个个加密，一个个输出组成密文。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CBC：Cipher Block Chaining（密码块链接模式）&lt;/strong&gt;，是一种循环模式，前一个分组的密文和当前分组的明文异或操作后再加密，这样做的目的是增强破解难度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCBC：Propagating Cipher Block Chaining（填充密码块链接模式）&lt;/strong&gt;，也称为明文密码块链接模式（Plaintext Cipher Block Chaining），是一种可以使密文中的微小更改在解密时导致明文大部分错误的模式，并在加密的时候也具有同样的特性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CFB：Cipher Feedback（密码反馈模式）&lt;/strong&gt;，可以将块密码变为自同步的流密码，类似于 CBC，CFB 的解密过程几乎就是颠倒的 CBC 的加密过程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OFB：Output Feedback（输出反馈模式）&lt;/strong&gt;，可以将块密码变成同步的流密码，它产生密钥流的块，然后将其与明文块进行异或，得到密文。与其它流密码一样，密文中一个位的翻转会使明文中同样位置的位也产生翻转。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CTR：Counter mode（计数器模式）&lt;/strong&gt;，也被称为 ICM 模式（Integer Counter Mode，整数计数模式）和 SIC 模式（Segmented Integer Counter），在 CTR 模式中，有一个自增的算子，这个算子用密钥加密之后的输出和明文异或的结果得到密文，相当于一次一密。这种加密方式简单快速，安全可靠，而且可以并行加密，但是在计算器不能维持很长的情况下，密钥只能使用一次。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考资料：维基百科：&lt;a href=&quot;https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation&quot;&gt;https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;填充方式 padding&lt;/h3&gt;
&lt;p&gt;块密码只能对确定长度的数据块进行处理，而消息的长度通常是可变的。因此部分模式最后一块数据在加密前需要进行填充。有数种填充方法，其中最简单的一种是在明文的最后填充空字符以使其长度为块长度的整数倍。常见填充方式有以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PKCS7&lt;/strong&gt;：在填充时首先获取需要填充的字节长度 = 块长度 - （数据长度 % 块长度）, 在填充字节序列中所有字节填充为需要填充的字节长度值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PKCS5&lt;/strong&gt;：PKCS5 作为 PKCS7 的子集算法，概念上没有什么区别，只是在 blockSize 上固定为 8 bytes，即块大小固定为 8 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZeroPadding&lt;/strong&gt;：在填充时首先获取需要填充的字节长度 = 块长度 - （数据长度 % 块长度）, 在填充字节序列中所有字节填充为 0 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISO10126&lt;/strong&gt;：在填充时首先获取需要填充的字节长度 = 块长度 - （数据长度 % 块长度），在填充字节序列中最后一个字节填充为需要填充的字节长度值，填充字节中其余字节均填充随机数值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ANSIX923&lt;/strong&gt;：在填充时首先获取需要填充的字节长度 = 块长度 - （数据长度 % 块长度），在填充字节序列中最后一个字节填充为需要填充的字节长度值，填充字节中其余字节均填充数字零。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;维基百科：&lt;a href=&quot;https://en.wikipedia.org/wiki/Padding_(cryptography)&quot;&gt;https://en.wikipedia.org/wiki/Padding_(cryptography)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PKCS7/PKCS5 填充算法：&lt;a href=&quot;https://segmentfault.com/a/1190000019793040&quot;&gt;https://segmentfault.com/a/1190000019793040&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Base64&lt;/h2&gt;
&lt;p&gt;简介：Base64 是一种用 64 个字符来表示任意二进制数据的方法。&lt;/p&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Base64 百度百科：&lt;a href=&quot;https://baike.baidu.com/item/base64/8545775&quot;&gt;https://baike.baidu.com/item/base64/8545775&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Base64 维基百科：&lt;a href=&quot;https://en.wikipedia.org/wiki/Base64&quot;&gt;https://en.wikipedia.org/wiki/Base64&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;MD5&lt;/h2&gt;
&lt;p&gt;简介：全称 MD5 消息摘要算法（英文名称：MD5 Message-Digest Algorithm），又称哈希算法、散列算法，由美国密码学家罗纳德·李维斯特（Ronald Linn Rivest）设计，于 1992 年作为 RFC 1321 被公布，用以取代 MD4 算法。摘要算法是单向加密的，也就是说明文通过摘要算法加密之后，是不能解密的。摘要算法的第二个特点密文是固定长度的，它通过一个函数，把任意长度的数据转换为一个长度固定的数据串（通常用16进制的字符串表示）。之所以叫摘要算法，它的算法就是提取明文重要的特征。所以，两个不同的明文，使用了摘要算法之后，有可能他们的密文是一样的，不过这个概率非常的低。&lt;/p&gt;
&lt;h2&gt;RSA&lt;/h2&gt;
&lt;p&gt;简介：英文名称：Rivest-Shamir-Adleman，是 1977 年由罗纳德·李维斯特（Ron Rivest）、阿迪·萨莫尔（Adi Shamir）和伦纳德·阿德曼（Leonard Adleman）一起提出的，RSA 就是他们三人姓氏开头字母拼在一起组成的，RSA 加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。它被普遍认为是目前比较优秀的公钥方案之一。RSA是第一个能同时用于加密和数字签名的算法，它能够抵抗到目前为止已知的所有密码攻击。&lt;/p&gt;
&lt;p&gt;参照 k哥爬虫 ：&lt;a href=&quot;https://mp.weixin.qq.com/s/4QTee0M9ukN6olgoR_LMug&quot;&gt;https://mp.weixin.qq.com/s/4QTee0M9ukN6olgoR_LMug&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>js环境</title><link>https://210214.xyz/posts/js-environment/</link><guid isPermaLink="true">https://210214.xyz/posts/js-environment/</guid><description>Node.js环境补环境配置</description><pubDate>Sun, 14 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;补环境&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;const jsdom = require(&quot;jsdom&quot;);
const { JSDOM } = jsdom;
const dom = new JSDOM(`&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;p&amp;gt;Hello world&amp;lt;/p&amp;gt;`);
window = dom.window;
var document = dom.window.document;
window.document = document;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装jsdom和canvas&lt;/h3&gt;
&lt;h4&gt;jsdom&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;npm install -g jsdom
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;canvas&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;npm install -g canvas
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>python解码</title><link>https://210214.xyz/posts/python-decoding/</link><guid isPermaLink="true">https://210214.xyz/posts/python-decoding/</guid><description>Python编码解码相关知识点</description><pubDate>Sun, 14 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;python 解码&lt;/h2&gt;
&lt;h3&gt;request 请求&lt;/h3&gt;
&lt;p&gt;原理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;字符串在Python内部的表示是&lt;strong&gt;unicode&lt;/strong&gt;编码，需要unicode编码作为中间件&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;eg、response 请求后得到的结果的编码，运行到python程序中首先是&lt;code&gt;unicode&lt;/code&gt;编码，先用response.text.encode去加载原本再网页中的编码，然后再将这个网页里使用的编码进行decode(&apos;utf8&apos;)就可以正常的显示了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;encode 用于在python程序中，unicode 对其他编码的处理，将python程序中的unicode编码encode得到常见的编码，想要输出的话还是要转成utf8，这就要用到decode函数了&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;decode函数是用于 常见编码转换成unicode编码的一种方式&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通用解码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;response.text.encode(response.encoding).decode(&apos;utf-8&apos;)
# response.encoding为原来的编码格式，encode后编码为原来的格式，decode后解码为&apos;utf-8&apos;

response.encoding = &apos;utf8&apos; # 将encoding直接转换成utf8
response.content.decode(&apos;utf8&apos;) # 二进制内容转换成utf8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.210214.xyz//random/image-20230514160231034.png&quot; alt=&quot;python编码&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;文件读写操作 codecs.open&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import codecs
with codecs.open(&apos;....txt&apos;, &apos;w&apos;, &apos;utf-8&apos;) as f:
    f.write(...)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Docker配置</title><link>https://210214.xyz/posts/docker-config/</link><guid isPermaLink="true">https://210214.xyz/posts/docker-config/</guid><description>Docker开机自启动和镜像源配置</description><pubDate>Mon, 08 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;docker&lt;/h2&gt;
&lt;h3&gt;docker设置开机自动重启并重新运行容器&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;设置docker服务自动重启：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl enable docker.service
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;docker容器时可以加如下参数来保证每次docker服务重启后容器也自动重启&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --restart=always
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果已经启动了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker update --restart=always
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重要的restart参数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;no - 容器退出时，不重启容器；&lt;/li&gt;
&lt;li&gt;on-failure - 只有在非0状态退出时才从新启动容器；如果容器由于错误而退出，则将其重新启动，非零退出代码表示错误&lt;/li&gt;
&lt;li&gt;unless-stopped - 重新启动容器，除非明确停止容器或者 Docker 被停止或重新启动&lt;/li&gt;
&lt;li&gt;always -只要容器停止了，就重新启动&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;docker-compose 启动&lt;/h3&gt;
&lt;h4&gt;启动命令&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo docker-compose up -d #前提需要有docker-compose.yml 文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;docker镜像源设置&lt;/h3&gt;
&lt;h4&gt;1.修改配置文件&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;创建或修改 /etc/docker/daemon.json 文件，修改为如下形式&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;registry-mirrors&quot;: [
        &quot;https://docker.mirrors.ustc.edu.cn&quot;,
        &quot;http://hub-mirror.c.163.com&quot;,
        &quot;https://registry.docker-cn.com&quot;
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2.加载重启docker&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;service docker restart
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Linux 登录配置</title><link>https://210214.xyz/posts/linux-ssh-config/</link><guid isPermaLink="true">https://210214.xyz/posts/linux-ssh-config/</guid><description>Linux服务器SSH登录配置教程，包括别名快速登录、免密登录、安全配置等。</description><pubDate>Mon, 08 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;登录服务器: ssh&lt;/h3&gt;
&lt;p&gt;ssh，&lt;code&gt;secure shell protocol&lt;/code&gt;，以更加安全的方式连接远程服务器。&lt;/p&gt;
&lt;p&gt;把以下 IP 地址替换为你云服务器的公网地址，并提供密码即可登录。&lt;/p&gt;
&lt;p&gt;但记住一个 IP 地址，这是一个反人性的操作，如果你有多个服务器需要管理呢？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ssh root@172.16.3.2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;配置别名快速登录：ssh-config&lt;/h3&gt;
&lt;p&gt;在&lt;strong&gt;本地客户端环境 (个人电脑) 上配置 ssh-config&lt;/strong&gt;，&lt;strong&gt;没有该文件则新建文件&lt;/strong&gt;。对自己管理的服务器起别名，可以更方便地登录多台云服务器，以下是关于 ssh-config 的配置文件&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果 windows 用户需要配置 ssh config，请先安装 &lt;a href=&quot;http://www.cygwin.com/install.html&quot;&gt;cygwin&lt;/a&gt;或者 mingw（git 自带）作为终端。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/ssh/ssh_config&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下是快速登录山月两个服务器 &lt;code&gt;shanyue&lt;/code&gt; 和 &lt;code&gt;training&lt;/code&gt; 的配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 修改 ssh 配置文件 ~/.ssh/config
# 172.16.3.2 是内网环境，此处仅做示例
Host shanyue
    HostName 172.16.3.2
    User root
# 请用真实 IP 地址替换以下的 PUBLIC_IP
# 并记得替换 User
Host training
    HostName &amp;lt;PUBLIC_IP&amp;gt;
    User root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置成功之后直接 ssh 就可以直接登录，是不很方便？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ssh shanyue
Last login: Wed Jun 15 20:09:14 2022 from 172.16.3.4
Welcome to Alibaba Cloud Elastic Compute Service !

[root@shanyue ~]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;免密登录：public-key 与 ssh-copy-id&lt;/h3&gt;
&lt;p&gt;如何实现远程服务器的免密登录需要两个条件:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;两个文件: 本地环境的 &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; 与 远程服务器的 &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;一个动作: 把本地文件 &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; 中内容复制粘贴到远程服务器 &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;如果本地没有 &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; 文件，则使用命令 &lt;code&gt;ssh-keygen&lt;/code&gt; 进行生成。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; 不能拥有其它用户（group、other）的写权限&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;总结成一句话，把自己的公钥放在远程服务器的 &lt;code&gt;authorized_keys&lt;/code&gt; 中&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;简单来说，就是 &lt;code&gt;Ctrl-C&lt;/code&gt; 与 &lt;code&gt;Ctrl-V&lt;/code&gt; 操作，不过还有一个更加有效率的工具: &lt;code&gt;ssh-copy-id&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;此时一个解决生产力的命令行工具应运而生: &lt;code&gt;ssh-copy-id&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ssh-copy-id shanyue
$ ssh shanyue
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安全性: 禁用密码登录&lt;/h3&gt;
&lt;p&gt;为了更大保障服务器的安全性，这里禁止密码登录。修改云服务器的 &lt;code&gt;sshd&lt;/code&gt; 配置文件：&lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;。其中 &lt;code&gt;PasswordAuthentication&lt;/code&gt; 设置为 &lt;code&gt;no&lt;/code&gt;，以此来禁用密码登录。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 编辑服务器端的 /etc/ssh/sshd_config
# 禁用密码登录
Host *
    PasswordAuthentication no
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;保持连接，防止断掉&lt;/h3&gt;
&lt;p&gt;除此之外，还可以通过一些配置来更好地优化我们连接服务器时的体验。&lt;/p&gt;
&lt;p&gt;我们可以通过 &lt;code&gt;man ssh_config&lt;/code&gt;，找到每一项的详细释义。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 编辑 ~/.ssh/config
Host *
    ServerAliveInterval 30
    TCPKeepAlive yes
    ServerAliveCountMax 6
    Compression yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ServerAliveInterval&lt;/code&gt; 将能够保持较长时间 &lt;code&gt;ssh&lt;/code&gt; 连接，不会使得程序在运行，结果因 ssh 超时而连接断开。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ServerAliveInterval&lt;/code&gt;：如果服务器 n 秒没有响应，则 ssh 客户端将发送数据包至 ssh 服务器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ServerAliveCountMax&lt;/code&gt;：直到发送了 n 次，服务器还没有响应，则断掉 ssh 连接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上配置代表，如果服务器不响应后，服务器在 &lt;code&gt;30 * 6&lt;/code&gt; 秒后将断开连接。&lt;/p&gt;
&lt;p&gt;另外也可以通过 &lt;code&gt;ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=6 $HOST&lt;/code&gt; 命令传递 ssh_config 配置。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Linux用Docker设置代理&lt;/h3&gt;
&lt;p&gt;将v2的端口设置好，并在&lt;code&gt;/etc/v2ray/config.json&lt;/code&gt;这个文件中配置好导出的客户端模块，最后一键运行这个代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name v2ray -v /etc/v2ray:/etc/v2ray -p 10890:10890 v2ray/official v2ray -config=/etc/v2ray/config.json
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;Docker 查看自己是否启动代理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果是http代理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl --proxy http://127.0.0.1:10890 www.google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果是socks代理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl --socks5 http://127.0.0.1:10890 www.google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;修改登录端口&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/ssh/sshd_config
#用&quot;/&quot;命令找到Port，并进行修改

sudo /etc/init.d/ssh restart
# 重启 ssh 连接服务！

# 修改完一定要记得打开修改过的端口
sudo ufw allow Port
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;关闭防火墙&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo ufw allow Port #指定端口进行开启
sudo ufw disable #先关闭防火墙 开启的话是enable
sudo ufw reset #重新设置
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Ubuntu 一键安装&lt;/h2&gt;
&lt;h3&gt;node&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install nodejs
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;npm&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo apt intsall npm
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;docker&lt;/h3&gt;
&lt;h4&gt;docker安装&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo curl -sSL https://get.daocloud.io/docker | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;docker-compose&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install docker-compose -y
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Node环境配置</title><link>https://210214.xyz/posts/node-environment/</link><guid isPermaLink="true">https://210214.xyz/posts/node-environment/</guid><description>Node.js环境配置和npm换源</description><pubDate>Mon, 08 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;#环境
D:\configuration\Node
D:\configuration\Node\node_global\node_modules
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# 换源
npm config set registry https://registry.npm.taobao.org
# 还原默认源：npm config set registry https://registry.npmjs.org/
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;#目录
npm config set prefix &quot;D:\configuration\Node\node_cache&quot;
npm config set cache &quot;D:\configuration\Node\node_cache&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Python经典书籍</title><link>https://210214.xyz/posts/python-books/</link><guid isPermaLink="true">https://210214.xyz/posts/python-books/</guid><description>Python学习书籍推荐</description><pubDate>Wed, 12 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;入门读物&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;《Python基础教程》&lt;/li&gt;
&lt;li&gt;《Python学习手册》&lt;/li&gt;
&lt;li&gt;《Python编程》&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;进阶读物&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;《Python核心编程》&lt;/li&gt;
&lt;li&gt;《流畅的Python》&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Web框架&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Django&lt;/li&gt;
&lt;li&gt;Flask&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;爬虫开发&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《用Python写网络爬虫》&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;数据分析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《利用Python进行数据分析》&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;机器学习&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《Python机器学习基础教程》&lt;/li&gt;
&lt;li&gt;《TensorFlow》&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Charles配置</title><link>https://210214.xyz/posts/charles-config/</link><guid isPermaLink="true">https://210214.xyz/posts/charles-config/</guid><description>Charles抓包工具HTTPS配置教程</description><pubDate>Wed, 12 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;charles 配置&lt;/h2&gt;
&lt;p&gt;之前文章讲的数据包主要是http协议，大家可以看到数据包并直接显示具体详细的内容：&lt;/p&gt;
&lt;p&gt;但是如果抓到的是https的报文，是没有办法直接显示的，你将看到的是乱码：&lt;/p&gt;
&lt;p&gt;那怎么抓取https的数据报文并正常显示报文内容信息呢？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步：安装证书&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果需要抓取并分析 Https 协议的数据报文，需要先安装 Charles 的 CA 证书。具体步骤如下：&lt;/p&gt;
&lt;p&gt;1、点击 Charles 的顶部菜单，选择 &quot;Help&quot; --&amp;gt; &quot;SSL Proxying&quot; --&amp;gt; &quot;Install Charles Root Certificate&quot;&lt;/p&gt;
&lt;p&gt;然后输入系统的帐号密码，即可在 KeyChain 看到添加好的证书。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步：安装浏览器证书&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;根据提示信息，需要先下载证书，再安装到浏览器中。&lt;/p&gt;
&lt;p&gt;所以，在浏览器地址栏输入&quot;chls.pro/ssl&quot;地址去下载证书&lt;/p&gt;
&lt;p&gt;然后在浏览器中安装这个下载好的证书，此处以chrome为例&lt;/p&gt;
&lt;h3&gt;第三步：开启SSL 代理&lt;/h3&gt;
&lt;p&gt;点击【Proxy】—&amp;gt; 【SSL proxying Settings】可以打开如下对话框：&lt;/p&gt;
&lt;p&gt;勾选&quot;Enable SSL Proxying&quot;，并在Include区域点击&quot;Add&quot;新建地址，在Host和Port区域填上&quot;*&quot;，表示匹配所有，那么就可以抓取所有的https数据报文。&lt;/p&gt;
</content:encoded></item><item><title>Hexo常用快捷键</title><link>https://210214.xyz/posts/hexo-commands/</link><guid isPermaLink="true">https://210214.xyz/posts/hexo-commands/</guid><description>Hexo命令行快捷键汇总</description><pubDate>Tue, 11 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;生成&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo s&lt;/code&gt; / &lt;code&gt;hexo server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;开始本地预览服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo d&lt;/code&gt; / &lt;code&gt;hexo deploy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;发布上传&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo clean &amp;amp;&amp;amp; hexo g &amp;amp;&amp;amp; hexo d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;组合生成发布命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo clean &amp;amp;&amp;amp; hexo g &amp;amp;&amp;amp; gulp &amp;amp;&amp;amp; hexo deploy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;最常用的组合命令，生成，压缩并发布&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo n&lt;/code&gt; / &lt;code&gt;hexo new &quot;postName&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;新建文章&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo new page &quot;pageName&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;新建页面&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo g&lt;/code&gt; / &lt;code&gt;hexo generate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;生成静态页面至public目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看帮助&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hexo version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看Hexo版本&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>代理IP测速</title><link>https://210214.xyz/posts/proxy-speed-test/</link><guid isPermaLink="true">https://210214.xyz/posts/proxy-speed-test/</guid><description>使用SPEEDTEST进行代理测速</description><pubDate>Tue, 11 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;请务必认准 .net 域名，不要使用 .cn 域名的来测试。&lt;/p&gt;
&lt;p&gt;请确认网页上显示的测试服务器的位置在中国大陆以外。如果仍显示国内地址，请开启全局代理模式。&lt;/p&gt;
&lt;p&gt;点击网页上的 GO 来进行测试。&lt;/p&gt;
&lt;h2&gt;无广告版本的站点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://www.speedtest.net/&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>代理IP测速</title><link>https://210214.xyz/posts/proxy-speed-test-new/</link><guid isPermaLink="true">https://210214.xyz/posts/proxy-speed-test-new/</guid><description>代理IP测速方法和无广告测速站点</description><pubDate>Tue, 11 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;SPEEDTEST : https://www.speedtest.net/&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;请务必认准 .net 域名，不要使用 .cn 域名的来测试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;请确认网页上显示的测试服务器的位置在中国大陆以外。如果仍显示国内地址，请开启全局代理模式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点击网页上的 GO 来进行测试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我自己常用的是无广告版本的站点：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;① &lt;a href=&quot;http://mybroadbandspeed.speedtestcustom.com/&quot;&gt;http://mybroadbandspeed.speedtestcustom.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;② &lt;a href=&quot;http://aaaaaa.speedtestcustom.com/&quot;&gt;http://aaaaaa.speedtestcustom.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;③ &lt;a href=&quot;http://rixcloud.speedtestcustom.com/&quot;&gt;http://rixcloud.speedtestcustom.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;④ &lt;a href=&quot;http://cordcloud.speedtestcustom.com/&quot;&gt;http://cordcloud.speedtestcustom.com/&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>常用算法模板</title><link>https://210214.xyz/posts/algorithm-templates/</link><guid isPermaLink="true">https://210214.xyz/posts/algorithm-templates/</guid><description>整理常用的算法模板，包括排序、二分、高精度、数据结构、图论、数学等算法。</description><pubDate>Sat, 11 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;快速排序算法模板&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;快排&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void quick_sort(int q[], int l, int r)
{
    if (l &amp;gt;= r) return;
    int i = l - 1, j = r + 1, x = q[l + r &amp;gt;&amp;gt; 1];
    while (i &amp;lt; j)
    {
        do i ++ ; while (q[i] &amp;lt; x);
        do j -- ; while (q[j] &amp;gt; x);
        if (i &amp;lt; j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;归并排序算法模板&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;void merge_sort(int q[], int l, int r)
{
    if (l &amp;gt;= r) return;
    int mid = l + r &amp;gt;&amp;gt; 1;
    merge_sort(q, l, mid);
    merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i &amp;lt;= mid &amp;amp;&amp;amp; j &amp;lt;= r)
        if (q[i] &amp;lt;= q[j]) tmp[k ++ ] = q[i ++ ];
        else tmp[k ++ ] = q[j ++ ];

    while (i &amp;lt;= mid) tmp[k ++ ] = q[i ++ ];
    while (j &amp;lt;= r) tmp[k ++ ] = q[j ++ ];

    for (i = l, j = 0; i &amp;lt;= r; i ++, j ++ ) q[i] = tmp[j];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;整数二分算法模板&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;bool check(int x) {/* … */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用：
int bsearch_1(int l, int r)
{
    while (l &amp;lt; r)
    {
        int mid = l + r &amp;gt;&amp;gt; 1;
        if (check(mid)) r = mid; // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}

// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用：
int bsearch_2(int l, int r)
{
    while (l &amp;lt; r)
    {
        int mid = l + r + 1 &amp;gt;&amp;gt; 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;浮点数二分算法模板&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;bool check(double x) {/* … */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    const double eps = 1e-6; // eps 表示精度，取决于题目对精度的要求
    while (r - l &amp;gt; eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;高精度加法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// C = A + B, A &amp;gt;= 0, B &amp;gt;= 0
vector&amp;lt;int&amp;gt; add(vector&amp;lt;int&amp;gt; &amp;amp;A, vector&amp;lt;int&amp;gt; &amp;amp;B)
{
    if (A.size() &amp;lt; B.size()) return add(B, A);
    vector&amp;lt;int&amp;gt; C;
    int t = 0;
    for (int i = 0; i &amp;lt; A.size(); i ++ )
    {
        t += A[i];
        if (i &amp;lt; B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }

    if (t) C.push_back(t);
    return C;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;高精度减法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// C = A - B, 满足A &amp;gt;= B, A &amp;gt;= 0, B &amp;gt;= 0
vector&amp;lt;int&amp;gt; sub(vector&amp;lt;int&amp;gt; &amp;amp;A, vector&amp;lt;int&amp;gt; &amp;amp;B)
{
    vector&amp;lt;int&amp;gt; C;
    for (int i = 0, t = 0; i &amp;lt; A.size(); i ++ )
    {
        t = A[i] - t;
        if (i &amp;lt; B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t &amp;lt; 0) t = 1;
        else t = 0;
    }
    while (C.size() &amp;gt; 1 &amp;amp;&amp;amp; C.back() == 0) C.pop_back();
    return C;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;高精度乘低精度&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// C = A * b, A &amp;gt;= 0, b &amp;gt;= 0
vector&amp;lt;int&amp;gt; mul(vector&amp;lt;int&amp;gt; &amp;amp;A, int b)
{
    vector&amp;lt;int&amp;gt; C;
    int t = 0;
    for (int i = 0; i &amp;lt; A.size() || t; i ++ )
    {
        if (i &amp;lt; A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }

    while (C.size() &amp;gt; 1 &amp;amp;&amp;amp; C.back() == 0) C.pop_back();

    return C;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;高精度除以低精度&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// A / b = C … r, A &amp;gt;= 0, b &amp;gt; 0
vector&amp;lt;int&amp;gt; div(vector&amp;lt;int&amp;gt; &amp;amp;A, int b, int &amp;amp;r)
{
    vector&amp;lt;int&amp;gt; C;
    r = 0;
    for (int i = A.size() - 1; i &amp;gt;= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() &amp;gt; 1 &amp;amp;&amp;amp; C.back() == 0) C.pop_back();
    return C;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;一维前缀和&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;二维前缀和&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角，(x2, y2)为右下角的子矩阵的和为：
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;一维差分&lt;/h2&gt;
&lt;p&gt;给区间[l, r]中的每个数加上c：B[l] += c, B[r + 1] -= c&lt;/p&gt;
&lt;h2&gt;二维差分&lt;/h2&gt;
&lt;p&gt;给以(x1, y1)为左上角，(x2, y2)为右下角的子矩阵中的所有元素加上c：
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c&lt;/p&gt;
&lt;h2&gt;位运算&lt;/h2&gt;
&lt;p&gt;求n的第k位数字: n &amp;gt;&amp;gt; k &amp;amp; 1
返回n的最后一位1：lowbit(n) = n &amp;amp; -n&lt;/p&gt;
&lt;h2&gt;双指针算法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;for (int i = 0, j = 0; i &amp;lt; n; i ++ )
{
    while (j &amp;lt; i &amp;amp;&amp;amp; check(i, j)) j ++ ;
    // 具体问题的逻辑
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见问题分类：
(1) 对于一个序列，用两个指针维护一段区间
(2) 对于两个序列，维护某种次序，比如归并排序中合并两个有序序列的操作&lt;/p&gt;
&lt;h2&gt;快速幂&lt;/h2&gt;
&lt;p&gt;求 m^k mod p，时间复杂度 O(logk)。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&amp;amp;1) res = res * t % p;
        t = t * t % p;
        k &amp;gt;&amp;gt;= 1;
    }
    return res;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>VMware虚拟机配置</title><link>https://210214.xyz/posts/vmware-config/</link><guid isPermaLink="true">https://210214.xyz/posts/vmware-config/</guid><description>VMware虚拟机配置教程，包括Ubuntu系统换源、静态IP配置、SSH连接设置等。</description><pubDate>Sat, 18 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;vm&lt;/h2&gt;
&lt;h3&gt;ubuntu 18&lt;/h3&gt;
&lt;h4&gt;换源&lt;/h4&gt;
&lt;h5&gt;1.查看发行版本信息&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;ubuntu 20.04&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 20.04.1 LTS
Release: 20.04
Codename: focal
#可以看到发行版本代号为 focal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ubuntu 18.04&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ lsb_release -c
Codename: bionic
#可以看到发行版本代号为 bionic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;部分ubuntu系统LTS版本代号&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ubuntu 16.04代号为：xenial
Ubuntu 17.04代号为：zesty
Ubuntu 18.04代号为：bionic
Ubuntu 19.04代号为：disco
Ubuntu 20.04代号为：focal
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.修改sources.list文件&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ubuntu 20.04&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#阿里源
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ubuntu 18.04&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#阿里源
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3.更新&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get update
sudo apt-get upgrade
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;静态ip&lt;/h4&gt;
&lt;h5&gt;1.首先查看虚拟机的各个网络字段&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;提取信息&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;上图所示我的NAT网络配置：
子网ip：192.168.230.0 #need 这里需要用子网ip这个同一个网段的不同地址，例如这里的就是192.168.230.*(1~255)
子网掩码：255.255.255.0
子网网关：182.168.230.2 #need
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其次还需要从自己主机查看本地网络的dns&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点击详细信息进行查看&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2.下面是对虚拟机的配置&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/netplan/01-network-manager-all.yaml #只要配置netplan下面的这个文件就行，如果没有这个同名的，可以找一下自己的目录,只要是yaml这个后缀的就行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;模板&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;network:
  version: 2
  renderer: NetworkManager
  ethernets:
    ens32:  #配置的网卡名称
      dhcp4: no    #dhcp4关闭
      dhcp6: no    #dhcp6关闭
      addresses: [192.168.230.128/24]   #设置本机IP及掩码
      optional: true
      gateway4: 192.168.230.2   #设置网关
      nameservers:
          addresses: [192.168.0.1]   #设置DNS
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;ssh连接&lt;/h4&gt;
&lt;h5&gt;1.关闭防火墙&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo ufw disable
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.安装OpenSSH&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install openssh-server openssh-client
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3.验证&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;netstat -tnl
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Python高级语法</title><link>https://210214.xyz/posts/python-advanced/</link><guid isPermaLink="true">https://210214.xyz/posts/python-advanced/</guid><description>Python高级语法知识点总结</description><pubDate>Wed, 08 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;lambda&lt;/h2&gt;
&lt;p&gt;匿名函数的语法，冒号前为参数，冒号后为返回值。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lambda x: x * x
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;列表生成式&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[x * x for x in range(1, 11)]
[x for x in range(1, 11) if x % 2 == 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;内置函数&lt;/h2&gt;
&lt;h3&gt;数学运算&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;abs&lt;/li&gt;
&lt;li&gt;round&lt;/li&gt;
&lt;li&gt;pow&lt;/li&gt;
&lt;li&gt;divmod&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;序列操作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;all&lt;/li&gt;
&lt;li&gt;any&lt;/li&gt;
&lt;li&gt;sorted&lt;/li&gt;
&lt;li&gt;reversed&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;对象操作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;hasattr&lt;/li&gt;
&lt;li&gt;getattr&lt;/li&gt;
&lt;li&gt;setattr&lt;/li&gt;
&lt;li&gt;isinstance&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;导入库&lt;/h2&gt;
&lt;h3&gt;json&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import json
json.dumps(data, ensure_ascii=False)  # 编码，支持中文
json.loads()  # 解码
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;datetime&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;from datetime import datetime
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;os&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;import os
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;线程池使用&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=5) as executor:
    executor.map(func, iterable)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;逆向常用&lt;/h2&gt;
&lt;p&gt;JavaScript Hook 调试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Object.defineProperty(document, &apos;cookie&apos;, {
  set: function(a) {
    debugger
  }
})
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>常用代理配置</title><link>https://210214.xyz/posts/proxy-config/</link><guid isPermaLink="true">https://210214.xyz/posts/proxy-config/</guid><description>各工具代理配置汇总</description><pubDate>Thu, 12 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Windows CMD&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;set http_proxy=http://yourProxyServer:port
set https_proxy=http://yourProxyServer:port
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Linux / Mac&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 设置代理
export http_proxy=http://yourProxyServer:port
export https_proxy=http://yourProxyServer:port

# 取消代理
unset http_proxy
unset https_proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 设置代理
git config --global http.proxy http://yourProxyServer:port

# 查看代理
git config --global --get http.proxy

# 删除代理
git config --global --unset http.proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;npm&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 设置镜像
npm config set registry https://registry.npm.taobao.org

# 设置代理
npm config set proxy http://yourProxyServer:port
npm config set https-proxy http://yourProxyServer:port

# 取消代理
npm config rm proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;yarn&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;yarn config set registry https://registry.npm.taobao.org
yarn config set proxy http://yourProxyServer:port
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;nvm&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;nvm proxy &quot;http://yourProxyServer:port&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bower (.bowerrc)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;directory&quot;: &quot;bower_components&quot;,
  &quot;proxy&quot;: &quot;http://yourProxyServer:port/&quot;,
  &quot;https-proxy&quot;: &quot;http://yourProxyServer:port/&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Gradle (gradle.properties)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;systemProp.http.proxyHost=yourProxyServer
systemProp.http.proxyPort=yourPort
systemProp.https.proxyHost=yourProxyServer
systemProp.https.proxyPort=yourPort
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Python pip&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 方式一：命令参数
pip install yourPackage --proxy http://yourProxyServer:port

# 方式二：配置文件 pip.ini
[install]
proxy=http://yourProxyServer:port
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;VSCode&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&quot;http.proxy&quot;: &quot;http://yourProxyServer:port&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Sublime&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&quot;http_proxy&quot;: &quot;http://yourProxyServer:port&quot;,
&quot;https_proxy&quot;: &quot;http://yourProxyServer:port&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;wget&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 临时
wget url -e http-proxy=yourProxyServer:port

# 永久：.wgetrc
http-proxy = yourProxyServer:port
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;curl&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 临时
curl url -x yourProxyServer:port

# 永久：_curlrc (Windows) 或 .curlrc (Linux)
proxy = yourProxyServer:port
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Golang go get&lt;/h2&gt;
&lt;p&gt;需设置系统变量 &lt;code&gt;http_proxy&lt;/code&gt; 以及 Git 代理 &lt;code&gt;git config --global http.proxy ...&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>正则入门</title><link>https://210214.xyz/posts/regex-intro/</link><guid isPermaLink="true">https://210214.xyz/posts/regex-intro/</guid><description>正则表达式是一种用于匹配字符串模式的强大工具，本文介绍正则表达式的基本语法和常用示例。</description><pubDate>Thu, 08 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;正则表达式简单示例&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;? #前面的字符需要出现0/1次
* #前面的字符可以出现0/多次
+ #前面的字符必须出现1次以上
{} #需要出现固定次数
 eg: {2,} #至少出现两次
 {2,6}#出现2-6次
() #出现多次-&amp;gt;() 是为了提取匹配的字符串。表达式中有几个()就有几个相应的匹配字符串。一般都是小括号后面加上大括号表示重复次数
| #或运算符
[xyz] #表示要求在区域里的字符
 eg: [a-zA-Z] #所有的字母
[^ ] #所有除了方括号内的字符
\d #数字
\w #英文字母
\s #空字符，回车键等
#上面三字符的大写都是表示取非
.* #任意字符
^a #以a字符为首，^表示以什么字符开头
$a #以a字符结尾，$表示以什么字符结尾
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>vue.js 拓展无法使用</title><link>https://210214.xyz/posts/vue-devtools-fix/</link><guid isPermaLink="true">https://210214.xyz/posts/vue-devtools-fix/</guid><description>解决Vue Devtools无法启用的问题</description><pubDate>Mon, 14 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;vue.js 拓展无法启用&lt;/h2&gt;
&lt;h3&gt;这里我以自己的谷歌浏览器演示&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;C:\Users\维磊\AppData\Local\Google\Chrome\User Data\Default\Extensions\nhdogjmejiglipccpnnnanhbledajbpd\6.4.5_0
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;在路径中点开文件夹找到 manifest.json 文件&lt;/h4&gt;
&lt;h4&gt;更改配置&lt;/h4&gt;
&lt;p&gt;更改文件中的字段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;persistent&quot;: true
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;我的 manifest.json 文件完整展示&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;background&quot;: {
        &quot;persistent&quot;: true,
        &quot;scripts&quot;: [&quot;build/background.js&quot;]
    },
    &quot;browser_action&quot;: {
        &quot;default_icon&quot;: {
            &quot;128&quot;: &quot;icons/128-gray.png&quot;,
            &quot;16&quot;: &quot;icons/16-gray.png&quot;,
            &quot;48&quot;: &quot;icons/48-gray.png&quot;
        },
        &quot;default_popup&quot;: &quot;popups/not-found.html&quot;,
        &quot;default_title&quot;: &quot;Vue Devtools&quot;
    },
    &quot;content_scripts&quot;: [
        {
            &quot;js&quot;: [&quot;build/hook.js&quot;],
            &quot;matches&quot;: [&quot;\u003Call_urls&amp;gt;&quot;],
            &quot;run_at&quot;: &quot;document_start&quot;
        },
        {
            &quot;js&quot;: [&quot;build/detector.js&quot;],
            &quot;matches&quot;: [&quot;\u003Call_urls&amp;gt;&quot;],
            &quot;run_at&quot;: &quot;document_idle&quot;
        }
    ],
    &quot;content_security_policy&quot;: &quot;script-src &apos;self&apos;; object-src &apos;self&apos;&quot;,
    &quot;description&quot;: &quot;Browser DevTools extension for debugging Vue.js applications.&quot;,
    &quot;devtools_page&quot;: &quot;devtools-background.html&quot;,
    &quot;icons&quot;: {
        &quot;128&quot;: &quot;icons/128.png&quot;,
        &quot;16&quot;: &quot;icons/16.png&quot;,
        &quot;48&quot;: &quot;icons/48.png&quot;
    },
    &quot;key&quot;: &quot;MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgJeMqfZu44CZ6O6SbpANnImOjQWgDPTyRXnvtYmAmZsC4o+mGZLWSdJph50Rdcipn+P66YvwrzN5ZSU8fz51d+C7OfCQiW3KnvBKYuSzF7AWciOx0crrVkCKZVgWh1GyEQS5Cpeifz/UZaXLoTqSqqFut/DeSCpMTFVIAvPksG3MGZI6jGIQd3CemEKUOXLUveNVbv8dEpxy/5NeUea4/wO6Kpa0zbEz1zQXrF0jOqsLC2d2hUOHPaAEc7h9uDal1cFsxG3e7ZQeGUPie3ho8bZfLPXYLj5dpDrRxVrxA92airJWOAQf8fqpKNm6SMw87NheU3xwmfV3EMpAWVen6wIDAQAB&quot;,
    &quot;manifest_version&quot;: 2,
    &quot;name&quot;: &quot;Vue.js devtools&quot;,
    &quot;permissions&quot;: [&quot;\u003Call_urls&amp;gt;&quot;, &quot;storage&quot;],
    &quot;update_url&quot;: &quot;https://clients2.google.com/service/update2/crx&quot;,
    &quot;version&quot;: &quot;6.4.5&quot;,
    &quot;version_name&quot;: &quot;6.4.5&quot;,
    &quot;web_accessible_resources&quot;: [&quot;devtools.html&quot;, &quot;devtools-background.html&quot;, &quot;build/backend.js&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;重启浏览器&lt;/h4&gt;
&lt;p&gt;后面重启就可以了&lt;/p&gt;
</content:encoded></item><item><title>Cpp配置</title><link>https://210214.xyz/posts/cpp-config/</link><guid isPermaLink="true">https://210214.xyz/posts/cpp-config/</guid><description>VSCode C++开发环境配置</description><pubDate>Fri, 11 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;cpp配置项&lt;/h2&gt;
&lt;h3&gt;vsc&lt;/h3&gt;
&lt;h4&gt;缩进&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;依次点击：文件-&amp;gt;首选项-&amp;gt;设置，然后输入 &lt;code&gt;C_Cpp: Clang_format_style&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;将默认的 file 改为 &lt;code&gt;{BasedOnStyle: Chromium, IndentWidth: 4}&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;配置c++11，&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;打开code runner 的配置文件，在语言配置项中配置cpp的选项为如下即可&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&quot;cpp&quot;: &quot;cd $dir &amp;amp;&amp;amp; g++ $fileName -std=c++11 -o $fileNameWithoutExt &amp;amp;&amp;amp; $dir$fileNameWithoutExt&quot;,
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>快速幂</title><link>https://210214.xyz/posts/quick-power/</link><guid isPermaLink="true">https://210214.xyz/posts/quick-power/</guid><description>快速幂是一种高效计算幂运算的算法，通过二进制分解将时间复杂度从O(n)降低到O(logn)。</description><pubDate>Tue, 08 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;快速幂核心思想&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;把所有的次方用不同的底数相乘 的方式进行计算&lt;/li&gt;
&lt;li&gt;一直自乘，当出现幂次数的二进制位是1时，答案乘上当前的已经存在的数&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;//非递归快速幂
int qpow(int a, int n){
    int ans = 1;
    while(n){
        if(n&amp;amp;1) //如果n的当前末位为1
            ans *= a; //ans乘上当前的a
        a *= a; //a自乘
        n &amp;gt;&amp;gt;= 1; //n往右移一位
    }
    return ans;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//泛型的非递归快速幂
template &amp;lt;typename T&amp;gt;
T qpow(T a, ll n)
{
    T ans = 1; // 赋值为乘法单位元，可能要根据构造函数修改
    while (n)
    {
        if (n &amp;amp; 1)
            ans = ans * a; // 这里就最好别用自乘了，不然重载完*还要重载*=，有点麻烦。
        n &amp;gt;&amp;gt;= 1;
        a = a * a;
    }
    return ans;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//求 m^k mod p，时间复杂度 O(logk)。
int qmi(int m, int k, int p)
{
    int res = 1 % p, t = m;
    while (k)
    {
        if (k&amp;amp;1) res = res * t % p;
        t = t * t % p;
        k &amp;gt;&amp;gt;= 1;
    }
    return res;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>JS补充</title><link>https://210214.xyz/posts/js-basics/</link><guid isPermaLink="true">https://210214.xyz/posts/js-basics/</guid><description>JavaScript基础知识补充，包括数组方法、ES6语法、函数、面向对象、DOM操作、事件处理等。</description><pubDate>Mon, 07 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1.数组&lt;/h2&gt;
&lt;h3&gt;数组的常用方法&lt;/h3&gt;
&lt;h4&gt;1. map&lt;/h4&gt;
&lt;p&gt;遍历数组。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;];
list.map(function (value, index) {
    console.log(&quot;第&quot; + (index + 1) + &quot;个元素是&quot; + value);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. push&lt;/h4&gt;
&lt;p&gt;在结尾追加元素。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;];
list.push(&quot;f&quot;);
console.log(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. sort&lt;/h4&gt;
&lt;p&gt;排序。&lt;/p&gt;
&lt;p&gt;数值：从小到大排序。
字符串：按首字母从 a~z 来排序。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = [1, 3, 6, 5, 2];
list.sort();
console.log(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. filter&lt;/h4&gt;
&lt;p&gt;过滤器。&lt;code&gt;newList = list.filter(function (item) {}&lt;/code&gt;的&lt;code&gt;item&lt;/code&gt;是数组的每个元素&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;例子 - 将数组中大于等于 3 的元素放到新的数组&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;var list = [1, 3, 6, 5, 2];
var newList = list.filter(function (item) {
    if (item &amp;gt;= 3) {
        return item;
    }
});
console.log(newList);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;5. join&lt;/h4&gt;
&lt;p&gt;连接数组。&lt;/p&gt;
&lt;p&gt;不加参数时，默认加逗号。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;];
var str = list.join();
console.log(str);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实现 abc，在 join 里面加参数，空字符串可以设成空的连接符&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var str = list.join(&quot;&quot;);
console.log(str);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实现 a+b+c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var str = list.join(&quot;+&quot;);
console.log(str);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;6.字符串split 方法&lt;/h4&gt;
&lt;p&gt;split 是字符串的拆分方法。&lt;/p&gt;
&lt;p&gt;split 不设参数时，默认生成一个数组。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var str = &quot;banana&quot;;
var list = str.split();
console.log(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;空字符串会拆分字符串&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = str.split(&quot;&quot;);
console.log(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按字符来拆分&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = str.split(&quot;n&quot;);
console.log(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;例子 - 把日期 &quot;2021-8-15&quot; 按 &quot;-&quot; 来拆分&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;var str = &quot;2021-8-15&quot;;
var list = str.split(&quot;-&quot;);
console.log(list);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;7.结合数组与对象&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;var list = [
    { name: &quot;小明&quot;, age: 2, sex: &quot;男&quot; },
    { name: &quot;小红&quot;, age: 2, sex: &quot;女&quot; },
    { name: &quot;小亮&quot;, age: 2, sex: &quot;男&quot; },
];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;获取数据：&lt;code&gt;list[0].name&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(list[0].age);
console.log(list[0].name);
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;例子 - 找出所有男同学，放入一个新的数组。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;方法 1 - 数组 filter 过滤器&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = [
    { name: &quot;小明&quot;, age: 2, sex: &quot;男&quot; },
    { name: &quot;小红&quot;, age: 2, sex: &quot;女&quot; },
    { name: &quot;小亮&quot;, age: 2, sex: &quot;男&quot; },
];
var newList = list.filter(function (item) {
    if (item.sex === &quot;男&quot;) {
        return item;
    }
});
console.log(newList);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;方法 2 - 数组 push 添加&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var list = [
    { name: &quot;小明&quot;, age: 2, sex: &quot;男&quot; },
    { name: &quot;小红&quot;, age: 2, sex: &quot;女&quot; },
    { name: &quot;小亮&quot;, age: 2, sex: &quot;男&quot; },
];
var newList = [];
for (var i = 0; i &amp;lt; list.length; i++) {
    if (list[i].sex === &quot;男&quot;) {
        newList.push(list[i]);
    }
}
console.log(newList);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.ES6&lt;/h2&gt;
&lt;h3&gt;模板字符串&lt;/h3&gt;
&lt;p&gt;反引号 &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持换行。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;let str = `hello
world`;
console.log(str);
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;支持嵌入变量。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;${}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;连接字符串&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let year = &quot;2020&quot;;
let month = &quot;10&quot;;
let date = &quot;10&quot;;
let result = `${year}年${month}月${date}日`;
console.log(result);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解构赋值&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;数组的解构赋值。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;[n,m]&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let [n, m] = [10, 20];
console.log(n);
console.log(m);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;例子 - 交换。让 n=20,m=10。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;定义一个临时变量，先把 n 放到 temp 里，再把 m 赋值给 n,最后再把 temp 赋值给 n。&lt;/p&gt;
&lt;p&gt;方法一&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let n = 10;
let m = 20;
let temp;
temp = n;
n = m;
m = temp;
console.log(n);
console.log(m);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;方法二（解构赋值）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let n = 10;
let m = 20;
[n, m] = [m, n];
console.log(n);
console.log(m);
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;对象的结构赋值（常用）。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;let { name, age } = { name: &quot;xiaoming&quot;, age: 10 };
console.log(name);
console.log(age);
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;let xm = { name: &quot;xiaoming&quot;, age: 10 };
function getName({ name }) {
    return name;
}
let result = getName(xm);
console.log(result);
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;通过解构赋值传递参数。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;3.函数&lt;/h2&gt;
&lt;h3&gt;1.闭包&lt;/h3&gt;
&lt;p&gt;闭包函数：声明在一个函数中的函数，叫做闭包函数。&lt;/p&gt;
&lt;p&gt;闭包：内部函数总是可以访问其所在的外部函数中声明的参数和变量，即使在其外部函数被返回之后。&lt;/p&gt;
&lt;p&gt;闭包的特性： 内部函数未执行完，外部函数即使执行完成，外部函数中的变量也不会被销毁。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自己总结&lt;/strong&gt;:在不需要展示内部变量的情况下，调用到内部函数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function fun1() {
    function fun2() {
        console.log(&quot;I&apos;m fun2&quot;);
    }
    return fun2;
}
const f = fun1();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;利用闭包实现了代码的封装。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function fun1() {
    let n = 10;
    let m = 20;
    function fun2() {
        return n + m;
    }
    return fun2;
}
const f = fun1();
const result = f();
console.log(result);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;代码封装&lt;/h4&gt;
&lt;p&gt;ES5 的一个模块化的语法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const module = (function () {
    let a = 10;
    let b = 20;
    function add() {
        return a + b;
    }
    return add;
})();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.箭头函数&lt;/h3&gt;
&lt;p&gt;作用： 简化写法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const add = (x) =&amp;gt; {
    return x * x;
};
const add = (x) =&amp;gt; x * x;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;const fun = function (x) {
    return x * x;
};

const fun = (x) =&amp;gt; {
    return x * x;
};

const fun = (x) =&amp;gt; x * x;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;例子 - 每秒输出一次名字&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;const cat = {
    name: &quot;miaomiao&quot;,
    sayName() {
        setInterval(() =&amp;gt; {
            console.log(this.name);
        }, 1000);
    },
};
cat.sayName();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;function&lt;/code&gt; 定义的函数， &lt;code&gt;this&lt;/code&gt; 取决于调用的函数。&lt;/p&gt;
&lt;p&gt;使用箭头函数， &lt;code&gt;this&lt;/code&gt; 取决于函数定义的位置。&lt;/p&gt;
&lt;p&gt;箭头函数和普通函数的&lt;code&gt;this&lt;/code&gt; 指向不同。&lt;/p&gt;
&lt;p&gt;普通函数指向的是调用该函数的对象。&lt;/p&gt;
&lt;p&gt;箭头函数：在哪里定义，&lt;code&gt;this&lt;/code&gt; 就指向谁。&lt;/p&gt;
&lt;h2&gt;4.面向对象&lt;/h2&gt;
&lt;h3&gt;ES5 构造函数&lt;/h3&gt;
&lt;p&gt;构造函数的函数名，首字母大写&lt;/p&gt;
&lt;p&gt;构造函数是用来创建对象用的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;function Dog(){}&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Dog(name, age) {
    this.name = name;
    this.age = age;
}
var dog = new Dog(&quot;旺柴&quot;, 2);
console.log(dog.name);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;原型对象&lt;/h3&gt;
&lt;p&gt;通过设置构造函数的&lt;code&gt;prototype&lt;/code&gt;属性，可以扩展构造函数生成的对象。&lt;/p&gt;
&lt;p&gt;通过原型对象，为构造函数生成的对象赋予新的方法。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dog.prototype.sayName = function () {};&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Dog(name, age) {
    this.name = name;
    this.age = age;
}
Dog.prototype.sayName = function () {
    console.log(`我的名字是${this.name}`);
};
var dog = new Dog(&quot;旺柴&quot;, 2);
var bigDog = new Dog(&quot;二哈&quot;, 3);
dog.sayName();
bigDog.sayName();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;原型链（继承）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Dog.prototype = new Animal()&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Animal(name) {
    this.name = name;
}
Animal.prototype.sayName = function () {
    console.log(`你好，我是${this.name}`);
};
Animal.prototype.sayHello = function () {
    console.log(&quot;hello&quot;);
};

function Dog(name) {
    this.name = name;
}
Dog.prototype = new Animal();

var dog = new Dog(&quot;旺柴&quot;);
dog.sayName();
dog.sayHello();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ES6 面向对象语法&lt;/h3&gt;
&lt;h4&gt;Class 关键字&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;constructor&lt;/code&gt;(ES6 的构造函数)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Dog {

    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(`我是${this.name}`);
    }
}
let dog = new Dog(&quot;旺柴&quot;, 2);
dog.sayName();
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;继承&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;extends&lt;/code&gt;关键字&lt;/p&gt;
&lt;p&gt;&lt;code&gt;super&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Animal {
    constructor(name) {
        this.name = name;
    }
    sayName() {
        console.log(`我是${this.name}`);
    }
}
class Dog extends Animal {
    constructor(name, age) {
        super(name);
        this.age = age;
    }
}
let dog = new Dog(&quot;旺柴&quot;, 2);
dog.sayName();
console.log(dog.age);
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>js逆向关键词</title><link>https://210214.xyz/posts/js-reverse-keywords/</link><guid isPermaLink="true">https://210214.xyz/posts/js-reverse-keywords/</guid><description>JavaScript逆向工程常用关键词检索技巧</description><pubDate>Sat, 15 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;特殊的关键词检索&lt;/h2&gt;
&lt;h3&gt;webpack打包&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;interceptors.request.use&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apply/call&lt;/code&gt; 用来找导出函数，找到加密函数后，自执行，用来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例地址 &lt;code&gt;https://developer.aliyun.com/article/1103664&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;主要结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var _e;
!(function(t) {
    var i = {};
    function e(s) {
        return t[s].call(n.exports, n, n.exports, e), n.loaded = !0, n.exports
    }
    _e = e;
})({
    encrypt: function(t, e, i) {},
    diaoyong: function(t, e, i) {}
});

function getkey(pass, time) {
    var diaoyong= _e(&quot;diaoyong&quot;);
    var new_diaoyong = new diaoyong();
    return new_diaoyong.encode(pass, time)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;非对称加密 RSA&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JSEncrypt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;new JSEncrypt(),JSEncrypt等，一般会便用JSEncrypt库，会有new一个实例对象的操作；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;搜索关键词setPublicKey、setKey、setPrivateKey、getPublicKey等，一般实现的代码里都含有设置密钥的过程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;normal&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;返回结果无法看懂，但页面显示正常&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JSON.parse/JSON.stringify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;btoa``base64&lt;/code&gt;加密， &lt;code&gt;atob&lt;/code&gt;解密&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new Date().getTime()&lt;/code&gt; 获取13位时间戳&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jsencrypt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;indexof&lt;/strong&gt; 通过window的可以查找&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Ajax入门</title><link>https://210214.xyz/posts/ajax-intro/</link><guid isPermaLink="true">https://210214.xyz/posts/ajax-intro/</guid><description>jQuery Ajax基本用法和参数详解</description><pubDate>Wed, 28 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Ajax&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$.ajax({
    type:&apos;POST&apos;, // 规定请求的类型（GET 或 POST）
    url:uploadV, // 请求的url地址
    dataType:&apos;json&apos;, //预期的服务器响应的数据类型
    data:{},//规定要发送到服务器的数据
    beforeSend:function(){ //发送请求前运行的函数（发送之前就会进入这个函数）
        // ....
    },
    success: function(result){ // 当请求成功时运行的函数
        //...
    },
    error:function(result){ //失败的函数
        //...
    },
    complete:function(){ //请求完成时运行的函数（在请求成功或失败之后均调用，即在 success 和 error 函数之后，不管成功还是失败 都会进这个函数）
        // ...
    }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;参数参考：&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;值/描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;async&lt;/td&gt;
&lt;td&gt;布尔值，表示请求是否异步处理。默认是 true。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;beforeSend(xhr)&lt;/td&gt;
&lt;td&gt;发送请求前运行的函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cache&lt;/td&gt;
&lt;td&gt;布尔值，表示浏览器是否缓存被请求页面。默认是 true。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;complete(xhr,status)&lt;/td&gt;
&lt;td&gt;请求完成时运行的函数（在请求成功或失败之后均调用，即在 success 和 error 函数之后）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contentType&lt;/td&gt;
&lt;td&gt;发送数据到服务器时所使用的内容类型。默认是：&quot;application/x-www-form-urlencoded&quot;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;context&lt;/td&gt;
&lt;td&gt;为所有 AJAX 相关的回调函数规定 &quot;this&quot; 值。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;data&lt;/td&gt;
&lt;td&gt;规定要发送到服务器的数据。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dataFilter(data,type)&lt;/td&gt;
&lt;td&gt;用于处理 XMLHttpRequest 原始响应数据的函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dataType&lt;/td&gt;
&lt;td&gt;预期的服务器响应的数据类型。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;error(xhr,status,error)&lt;/td&gt;
&lt;td&gt;如果请求失败要运行的函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;global&lt;/td&gt;
&lt;td&gt;布尔值，规定是否为请求触发全局 AJAX 事件处理程序。默认是 true。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ifModified&lt;/td&gt;
&lt;td&gt;布尔值，规定是否仅在最后一次请求以来响应发生改变时才请求成功。默认是 false。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jsonp&lt;/td&gt;
&lt;td&gt;在一个 jsonp 中重写回调函数的字符串。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jsonpCallback&lt;/td&gt;
&lt;td&gt;在一个 jsonp 中规定回调函数的名称。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;password&lt;/td&gt;
&lt;td&gt;规定在 HTTP 访问认证请求中使用的密码。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;processData&lt;/td&gt;
&lt;td&gt;布尔值，规定通过请求发送的数据是否转换为查询字符串。默认是 true。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;scriptCharset&lt;/td&gt;
&lt;td&gt;规定请求的字符集。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;success(result,status,xhr)&lt;/td&gt;
&lt;td&gt;当请求成功时运行的函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;timeout&lt;/td&gt;
&lt;td&gt;设置本地的请求超时时间（以毫秒计）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;traditional&lt;/td&gt;
&lt;td&gt;布尔值，规定是否使用参数序列化的传统样式。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;type&lt;/td&gt;
&lt;td&gt;规定请求的类型（GET 或 POST）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;规定发送请求的 URL。默认是当前页面。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;username&lt;/td&gt;
&lt;td&gt;规定在 HTTP 访问认证请求中使用的用户名。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;xhr&lt;/td&gt;
&lt;td&gt;用于创建 XMLHttpRequest 对象的函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>java 跨域请求</title><link>https://210214.xyz/posts/java-cors/</link><guid isPermaLink="true">https://210214.xyz/posts/java-cors/</guid><description>Spring Boot项目中解决跨域的3种方案</description><pubDate>Mon, 05 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;跨域请求&lt;/h2&gt;
&lt;p&gt;同源策略：协议、域名、端口 3 个都相同就是同源&lt;/p&gt;
&lt;p&gt;Spring Boot 项目中解决跨域的 3 种方案&lt;/p&gt;
&lt;h3&gt;1、在目标方法上添加 @CrossOrigin 注解&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@GetMapping(&quot;/list&quot;)
@CrossOrigin
public List&amp;lt;String&amp;gt; list(){
    List&amp;lt;String&amp;gt; list = Arrays.asList(&quot;Java&quot;,&quot;C++&quot;,&quot;Go&quot;);
    return list;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2、添加 CORS 过滤器&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin(&quot;*&quot;);
        corsConfiguration.addAllowedHeader(&quot;*&quot;);
        corsConfiguration.addAllowedMethod(&quot;*&quot;);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration(&quot;/**&quot;, corsConfiguration);
        return new CorsFilter(source);
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3、实现 WebMvcConfigurer 接口，重写 addCorsMappings 方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
public class CorsConfiguration implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping(&quot;/**&quot;)
                .allowedOriginPatterns(&quot;*&quot;)
                .allowedMethods(&quot;GET&quot;,&quot;POST&quot;,&quot;PUT&quot;,&quot;DELETE&quot;,&quot;HEAD&quot;,&quot;OPTIONS&quot;)
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders(&quot;*&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>java IO流</title><link>https://210214.xyz/posts/java-io/</link><guid isPermaLink="true">https://210214.xyz/posts/java-io/</guid><description>IO是指Input/Output，即输入和输出。本文详细介绍Java中的字节流、字符流、功能流、转换流、基本数据类型流和对象流的使用方法。</description><pubDate>Mon, 05 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;IO是指Input/Output，即输入和输出。&lt;/p&gt;
&lt;h2&gt;字节输入流（常用）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Inputstream&lt;/code&gt;是输入流的抽象父类，类里面主要就是&lt;code&gt;read&lt;/code&gt;方法与&lt;code&gt;close&lt;/code&gt;方法，需要去找子类的实例，实现其方法；&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
  File file = new File(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\receive.jpg&quot;);//传一个路径
  InputStream is = new FileInputStream(file);//构建流
  int read = is.read();//按字节来读入流
  System.out.println(read);//结果：255(ascil码)
  is.close();//关闭流
}
//read方法如果没有读到就返回-1
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//通过while循环来改善每个字节的读入
public static void main(String[] args) throws IOException {
    File file = new File(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\receive.jpg&quot;);
    InputStream is = new FileInputStream(file);
    int len ;
    while((len =is.read())!=-1){//当到达-1时候就会停止
        System.out.println((char)len);
    }
    is.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;字节读入优化（每次读入一个字节效率太低，通过字符数组缓冲）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\src\\test.txt&quot;);//直接构建文件
    byte[] bytes = new byte[1024];//新建一个存储数组
    int len = fis.read(bytes);//记录长度
    System.out.println(new String(bytes,0,len));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//可以通过while循环来构建，循环去读入
while ((len = fis.read(bytes)) != -1) {
    System.out.println(new String(bytes, 0, len));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字节输出流（常用）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Ouputstream&lt;/code&gt;是输入流的抽象父类，类里面主要就是&lt;code&gt;write&lt;/code&gt;方法与&lt;code&gt;close&lt;/code&gt;方法，需要去找子类的实例，实现其方法；&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\src\\text02.txt&quot;);//输出路径
    fos.write(97);//写入字符
    fos.close();//关闭流
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\src\\text02.txt&quot;);
    byte[] bytes = &quot;你好&quot;.getBytes();//通过getBytes()方法获取字符串数组
    fos.write(bytes);//按数组的形式写入
    fos.close();
}
//会默认覆盖原来内容，如果想要是追加在字节输出流的参数中传入true，声明追加
//new FileOutputStream(&quot;&quot;,true);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;文件拷贝（常用）&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream(&quot;receive.jpg&quot;);
    FileOutputStream fos = new FileOutputStream(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\receive2.jpg&quot;);
    int len;
    byte[] bytes = new byte[1024];
    while((len =fis.read(bytes))!=-1){
        fos.write(bytes,0,len);
    }

    fos.close();
    fis.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字符流&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Reader&lt;/code&gt;和&lt;code&gt;Writer&lt;/code&gt;是字符输入输出的抽象父类，还是两个主要方法&lt;code&gt;read&lt;/code&gt;,&lt;code&gt;write&lt;/code&gt;,&lt;code&gt;close&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FileReader&lt;/code&gt;,&lt;code&gt;FileWriter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;注：字符流一般就是对纯文本的处理拷贝&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader(&quot;D:\\project\\java\\execrise\\project 01\\project0.1\\src\\test.txt&quot;);
    FileWriter wr = new FileWriter(&quot;src\\IO_Demo\\text01.txt&quot;);
    char[] chars= new char[1024];//这里变成了char数组
    int len ;
    while ((len = fr.read(chars))!=-1){
        wr.write(chars,0,len);
    }
    wr.close();
    fr.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;功能流&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;缓冲流是功能流中的一种，包裹节点流使用&lt;/li&gt;
&lt;li&gt;增强节点流的读写效率，提高性能&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;InputStream&lt;/code&gt;---&amp;gt;&lt;code&gt;BufferedInputstream&lt;/code&gt;字节输入流缓冲流
&lt;code&gt;OutputStream&lt;/code&gt; ---&amp;gt;&lt;code&gt;BufferedOutputstream&lt;/code&gt;字节输出流缓冲流
&lt;code&gt;Reader&lt;/code&gt;---&amp;gt;&lt;code&gt;BufferedReader&lt;/code&gt;字符输入缓冲流
&lt;code&gt;Writer&lt;/code&gt;---&amp;gt;&lt;code&gt;BufferedWriter&lt;/code&gt;字符输出流的缓冲流&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;只有字符缓冲流有新增功能，&lt;code&gt;readline&lt;/code&gt;()-&amp;gt;一行一行的读；&lt;code&gt;newline&lt;/code&gt;()-&amp;gt;换行&lt;/li&gt;
&lt;li&gt;因为&lt;code&gt;readline&lt;/code&gt;返回值是&lt;code&gt;String&lt;/code&gt;类型，所以改成用不等于&lt;code&gt;null&lt;/code&gt;判断&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(&quot;src\\test.txt&quot;));//包裹节点流
    BufferedWriter bw = new BufferedWriter(new FileWriter(&quot;src\\test02.txt&quot;));//包裹节点流
    String msg =null;
    while((msg=br.readLine())!=null){
        bw.write(msg);
        bw.newLine();//换行
    }
    bw.close();
    br.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;转换流&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;转换流–&amp;gt;功能流&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;InputStreamReader&lt;/code&gt;:是从字节流到字符流的桥接器：只能从字节到字符，不能从字符到字节&lt;/p&gt;
&lt;p&gt;作用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;乱码问题。设置编码格式&lt;/li&gt;
&lt;li&gt;流的转换&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;构造器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;InputStreamReader&lt;/code&gt;(&lt;code&gt;Inputstream&lt;/code&gt; in)创建一个使用默认字符集的&lt;code&gt;InputStreamReader&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;InputStreamReader&lt;/code&gt;(&lt;code&gt;InputStream&lt;/code&gt; in,String &lt;code&gt;charsetName&lt;/code&gt;)创建一个使用指定&lt;code&gt;charset&lt;/code&gt;,解决乱码&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(&quot;src\\test.txt&quot;)), &quot;gbk&quot;));
    //先读入文件，buffer流优化，通过转换流将字节流转换成字符流，然后再buffer流优化
    //同时设置了读入的字符编码gbk
    BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(&quot;src\\test02.txt&quot;)), &quot;gbk&quot;));
    String msg =null;
    while((msg=br.readLine())!=null){
        wr.write(msg);
    }
    wr.flush();
    wr.close();
    br.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;基本数据类型流&lt;/h2&gt;
&lt;p&gt;基本数据类型流|&lt;code&gt;Data&lt;/code&gt;流（节点流）：基本数据类型+String&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是字节流功能流的一种&lt;/li&gt;
&lt;li&gt;功能：能够是节点流具有传输基本数据类型+数据的能力&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DataInputstream&lt;/code&gt; 基本数据类型输入流&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DataOputputstream&lt;/code&gt; 基本数据类型输出流&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;//输出
public static void WriteDate(String desc) throws IOException {
    DataOutputStream dos = new DataOutputStream(new FileOutputStream(&quot;src\\text02.txt&quot;));
    int a =1;
    boolean flag =false;
    char ch =&apos;a&apos;;
    String str =&quot;你好&quot;;
    dos.writeInt(a);//写入int类型
    dos.writeBoolean(flag);//写入bool类型
    dos.writeChar(ch);//写入字符类型
    dos.writeUTF(str);//写入字符串类型
    dos.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;//输出
public static void ReadDate(String src) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(&quot;src\\text.txt&quot;));
    //要与上面的写入对应，先写入先读，否则会识别不出
    int a = dis.readInt();
    boolean flag = dis.readBoolean();
    char ch  = dis.readChar();
    String str = dis.readUTF();

    dis.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;对象流&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对象流|Object流：所有类型+对象类型&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ObjectInputstream&lt;/code&gt;对象字节输入流|反序列化输入流
&lt;code&gt;OjbectOutputstream&lt;/code&gt;对象字节输出流|序列化输出流&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;序列化：&lt;code&gt;java&lt;/code&gt;对象类型的信息状态转换成为一个可存储，可传输的信息状态的过程
反序列化：将已经储存的那个信息状态还原&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;//序列化一个int数组
public static void Obj_Output(String desc) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(desc)));
    int []arr = {1,2,3,4};
    oos.writeObject(arr);
    oos.flush();
    oos.close();
}
//反序列化这个int数组
public static void  Obj_Input(String src) throws IOException, ClassNotFoundException {
    ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(src)));
    int []a = (int[]) ois.readObject();
    System.out.println(Arrays.toString(a));
    ois.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想要序列化自己定义的类，需要&lt;code&gt;implement&lt;/code&gt; &lt;code&gt;Serializable&lt;/code&gt;接口，没有什么实质性的用处，就是标志可序列化&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    private String name;
    private int id;
}
public static void Obj_Output(String desc) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(desc)));
    Stu xixi = new Stu(&quot;xixi&quot;, 10);
    oos.writeObject(xixi);
    oos.flush();
    oos.close();
}
public static void Obj_Output(String desc) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(desc)));
        Stu xixi = new Stu(&quot;xixi&quot;, 10);
        oos.writeObject(xixi);
        oos.flush();
        oos.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果想要一个属性不需要被序列化，那么要在这个属性前面添加&lt;code&gt;transient&lt;/code&gt;关键字&lt;/li&gt;
&lt;li&gt;static修饰的成员不会被序列化&lt;/li&gt;
&lt;li&gt;父类实现了序列化接口，子类所有的内容都能序列化&lt;/li&gt;
&lt;li&gt;子类实现了序列化接口，子类只能序列化自己的内容，不能序列化父类中继承的内容&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Linux 基本命令</title><link>https://210214.xyz/posts/linux-commands/</link><guid isPermaLink="true">https://210214.xyz/posts/linux-commands/</guid><description>Linux入门基础命令大全，包括文件操作、用户管理、进程管理、JDK配置、防火墙配置、MySQL安装等。</description><pubDate>Mon, 05 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Linux入门&lt;/h2&gt;
&lt;h3&gt;命令&lt;/h3&gt;
&lt;h4&gt;1.基本命令&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;# :代表系统管理员
$ :代表普通的用户
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;ifconfig
clear #清屏
cd / #进入根
ll #显示所有目录信息
su #可以先进home查看所有用户信息，如果有可以用su加上普通用户的名称进入用户
 #普通用户进入root用户需要密码，而且还看不到输入的密码
pwd #打印目录
cd .. #返回上一层
poweroff #关机
reboot #重启
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2.文件和文件&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;mkdir #创建文件夹
touch (文件名.后缀)#创建文件
mv 被移动的文件 路径 #mv ./文件名.后缀 目录 移动文件
 #mv ./文件名.后缀 目录 文件名.后缀 移动文件并修改文件名
 #mv ./文件名.后缀 ./新的文件名.后缀 重命名
rm #rm 文件.后缀 一处文件
#rm -r 移除文件夹，并删除文件夹下面的所有文件和文件夹
#rm -rf 强制删除，不需要询问，一般真的删都是这个递归删除
#项目变更记得先打个包备份，因为Linux下面rm之后真的就很难很难恢复了
cp 被复制的文件 路径 #cp ./文件名.后缀 目录 移动文件 (这个没办法边移动边改名称)
find 路径 -type f| grep profile
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.文件内容的操作&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;vim三种模式&lt;/p&gt;
&lt;p&gt;一般模式，编辑模式，底行模式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;一般模式： #复制：yy 粘贴：p 删除：dd 撤销：u 反撤销：ctrl+r
 #跳转文件第一行：gg 跳转文件最后一行：G
 #搜索关键字： /关键字 (对于存在多个关键字用n进行跳转)
 编辑模式： #输入i/a/o进入编辑模式，esc退出编辑模式，变成一般模式
 底行模式： #输入：进入底行模式，wq指令保存并退出 ，set number/nonumber显/不显示行号，
 #输入数字直接就可以进入第几行 关闭高亮：noh
 #替换 开始行数/$s(结束行数，$s是最后一行) /原来的关键字/新的关键字/g(全局替换，g不加就不是全局)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cat 文件名.后缀 #查看文件 cat -n 文件名.后缀 显示行号查看
 #cat -n 文件名.后缀 显示行号查看
tail 文件名.后缀 #tail一般是打印日志，看tomcat的日志一般就用tail命令
 #正常是需要用tail -f 文件名.后缀
 #就是只要有新日志就会立刻打印，动态打印，Ctrl+z退出
more 文件名.后缀 #阅读模式，space可以跳到下一页，按q退出
nl 文件名.后缀 #从最后一行开始展示文件 基本用cat就可以了
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4.文件的压缩解压缩&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;tar 命令：打包文件或文件夹
选项：
# -c 创建一个打包文件
# -X 解开一个打包文件
# -Z 使用gzip压缩文件
# -j 使用bzip2压缩文件
# -V 压缩过程显示文件
# -f 使用文档名
# 常用命令 ：创建 tar -zcf 打包名.tar.gz (后缀尽量别写错，后面不然很难解压) 打包的文件
# ：解压 tar -zxf 包名.后缀
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;zip #压缩 zip 打包名.zip 打包的文件
unzip #解压 unzip 包名.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;5. 用户组&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;#Linux用户组的操作
groupadd #添加 groupadd 组名
grouppmod #修改 groupmod -n 新组名 旧组名
groupdel #删除 groupdel 组名
groups # 显示所在组名
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;#Linux 用户的操作
useradd #添加 useradd [选项] 用户名 创建的用户都放在/home下
#选项： -g 设置用户组 -G 设置用户组列表，多个用户组用，隔开
# -u 手动指定用户1d,必须唯一且大于499 -p 为新用户指定密码，但是该密码需要设置为MD5加密后的
usermod #修改 usermod [选项] 用户名
userdel #删除 userdel [选项] 用户名
passwd #设置用户的密码： passwd 用户名
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;关于用户权限展示：drwxrwxrwx ：&lt;/p&gt;
&lt;p&gt;每个都由三个部分组成:当前用户的权限:&lt;strong&gt;u&lt;/strong&gt;，与自己同组用户的权限:&lt;strong&gt;g&lt;/strong&gt;，非同组用户的权限:&lt;strong&gt;o&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;d是指现在是表示目录还是文件如果是文件的话就是-&lt;/p&gt;
&lt;p&gt;r是具有读的权限&lt;/p&gt;
&lt;p&gt;w是具有写的权限&lt;/p&gt;
&lt;p&gt;x是具有执行的权限(execute)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;#字符授权模式
chmod #chmod (组名)u/g/o (添加/移除/覆盖) +/-/= (权限名) w/r/x 文件.后缀
#数字授权模式
r - 4 w - 2 x - 1
chmod #7以内的加减法 eg. chmod 700 文件名.后缀 即u组有wrx权限，其他什么权限都没有
 # -R 可以递归的加文件夹里面子文件权限
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;6.进程管理&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;ps -ef # 显示所有进程信息，连同命令行
ps -ef | grep ssh # ps 与grep 常用组合用法，查找特定进程
kill #kill pid(进程编号) 终止进程
 #kill -9 pid 强制终止
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;#服务的操作
systemctl start|stop|restart|enable|disable|status 服务名 #查看服务命令
 #如查看firewalld
#端口号查看
yum -y insatll net-tools #下载netstat
netstat -ntlp #查看当前所有tcp端口
netstat -ntlp|grep 端口号 #查看当前对应tcp端口
#访问地址
curl 地址
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;7.配置jdk&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;如果想删除原来的jdk&lt;/p&gt;
&lt;p&gt;rpm -qa | grep -i java | xargs -n1 rpm -e –nodeps&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rpm -qa：查询所安装的所有rpm软件包&lt;/li&gt;
&lt;li&gt;grep -i：忽略大小写&lt;/li&gt;
&lt;li&gt;xargs -n1：表示每次只传递一个参数&lt;/li&gt;
&lt;li&gt;rpm -e –nodeps：强制卸载软件&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;将jdk解压到记住的路径 我选择的是&lt;code&gt;/usr/local/soft/java&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;去&lt;code&gt;/etc&lt;/code&gt; 用vim打开 &lt;code&gt;profile&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;#定义JAVA_HOME
export JAVA_HOME=/usr/local/soft/java/jdk1.8.0_202
#把JAVA_HOME添加到PATH
export PATH=$JAVA_HOME/bin:$PATH
#$表示使用环境变量.   :相当于是分隔符   因为前面是定义所以还需要将他添加上去
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;重新加载profile文件 &lt;code&gt; source /etc/profile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;验证是否成功&lt;code&gt;Java -version&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;8.配置防火墙&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;防火墙配置
&lt;blockquote&gt;
&lt;p&gt;配置文件 ： &lt;code&gt;/usr/lib/firewalld/services/ssh.xml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;添加开放端口：&lt;code&gt;&amp;lt;port protocol=&quot;tcp&quot; port=&quot;8080&quot;/&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;重启防火墙&lt;code&gt;systemctl restart firewalld&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;9.mysql创建&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rpm -qa|grep mariadb&lt;/code&gt;查看本地有没有这个文件 ，如果有需要删除&lt;code&gt;rpm -e mariadb-libs-5.5.68-1.el7.x86_64 --nodeps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;安装MySQL&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;rpm -ivh mysql-community-common-8.0.20-1.el7.x86_64.rpm  --nodeps --force
rpm -ivh mysql-community-libs-8.0.20-1.el7.x86_64.rpm  --nodeps --force
rpm -ivh mysql-community-client-8.0.20-1.el7.x86_64.rpm --nodeps --force
rpm -ih mysql-community-server-8.0.20-1.el7.x86_64.rpm  --nodeps --force
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;新装的MySQL密码是随机的&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;chown mysql:mysql /var/lib/mysql -R
systemctl start mysqld.service
systemctl enable mysqld
# 首先启动mysql，查看最开始的密码
cat /var/log/mysqld.log |grep password#查看密码，通过这个密码登录MySQL
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;ALTER USER &apos;root&apos;@&apos;localhost&apos; IDENTIFIED WITH mysql_native_password BY &apos;root&apos;; # 重新设置密码为root
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;开放远程连接&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;use mysql;
update user set host=&apos;%&apos; where user =&apos;root&apos;; #开放远程
FLUSH PRIVILEGES;#刷新
GRANT ALL PRIVILEGES ON *.* TO &apos;root&apos;@&apos;%&apos;WITH GRANT OPTION;#授权语句
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;防火墙的设置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;vim /usr/lib/firewalld/services/ssh.xml #添加3306的端口
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;navicat通过ip连接虚拟机，创建数据库，导入用的表&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>SSM框架整合</title><link>https://210214.xyz/posts/ssm-framework/</link><guid isPermaLink="true">https://210214.xyz/posts/ssm-framework/</guid><description>Spring+SpringMVC+MyBatis框架整合配置</description><pubDate>Wed, 31 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;1.maven配置--&amp;gt;pom.xml&lt;/h3&gt;
&lt;p&gt;导入依赖及Maven资源过滤设置&lt;/p&gt;
&lt;h3&gt;2.webapp--&amp;gt;web.xml&lt;/h3&gt;
&lt;p&gt;配置DispatcherServlet和字符编码过滤器&lt;/p&gt;
&lt;h3&gt;3.mybatis与spring整合--&amp;gt;spring.xml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;context:property-placeholder location=&quot;classpath:databases.properties&quot;/&amp;gt;

&amp;lt;bean id=&quot;dataSource&quot; class=&quot;com.mchange.v2.c3p0.ComboPooledDataSource&quot;&amp;gt;
    &amp;lt;property name=&quot;driverClass&quot; value=&quot;${jdbc.driver}&quot;/&amp;gt;
    &amp;lt;property name=&quot;jdbcUrl&quot; value=&quot;${jdbc.url}&quot;/&amp;gt;
    &amp;lt;property name=&quot;user&quot; value=&quot;${jdbc.username}&quot;/&amp;gt;
    &amp;lt;property name=&quot;password&quot; value=&quot;${jdbc.password}&quot;/&amp;gt;
    &amp;lt;property name=&quot;maxPoolSize&quot; value=&quot;30&quot;/&amp;gt;
    &amp;lt;property name=&quot;minPoolSize&quot; value=&quot;10&quot;/&amp;gt;
    &amp;lt;property name=&quot;autoCommitOnClose&quot; value=&quot;false&quot;/&amp;gt;
    &amp;lt;property name=&quot;checkoutTimeout&quot; value=&quot;1000&quot;/&amp;gt;
    &amp;lt;property name=&quot;acquireRetryAttempts&quot; value=&quot;2&quot;/&amp;gt;
&amp;lt;/bean&amp;gt;

&amp;lt;bean id=&quot;sqlSessionFactory&quot; class=&quot;org.mybatis.spring.SqlSessionFactoryBean&quot;&amp;gt;
    &amp;lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&quot;mapperLocations&quot; value=&quot;classpath:com/Lei/dao/*.xml&quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&quot;configLocation&quot; value=&quot;classpath:mybatis.xml&quot;&amp;gt;&amp;lt;/property&amp;gt;
&amp;lt;/bean&amp;gt;

&amp;lt;bean class=&quot;org.mybatis.spring.mapper.MapperScannerConfigurer&quot;&amp;gt;
    &amp;lt;property name=&quot;basePackage&quot; value=&quot;com.Lei.dao&quot;&amp;gt;&amp;lt;/property&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为什么是三个bean：一个是首先jdbc连接数据库的信息填写，第二个是sql工厂，里面包含的东西都是与sql有关的，首先是读取数据源，其次是对mapper.xml文件的扫描（里面包含了底层的sql语句），还有一个是对mybatis文件的解析，第三个bean就是扫描自定义接口，扫的是dao层同级别的&lt;/p&gt;
&lt;p&gt;同时这里的整合可以通过&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;context:property-placeholder location=&quot;classpath:databases.properties&quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来导入jdbc的连接，对应的databases配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=true&amp;amp;useUnicode=true&amp;amp;characterEncoding=utf8&amp;amp;serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.mybatis自己的管理--&amp;gt;mybatis.xml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE configuration PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot; &quot;http://mybatis.org/dtd/mybatis-3-config.dtd&quot;&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;settings&amp;gt;
        &amp;lt;setting name=&quot;logImpl&quot; value=&quot;STDOUT_LOGGING&quot;/&amp;gt;
    &amp;lt;/settings&amp;gt;
    &amp;lt;typeAliases&amp;gt;
        &amp;lt;package name=&quot;com.Lei.entity&quot;/&amp;gt;
    &amp;lt;/typeAliases&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.springmvc的自动扫描和视图配置--&amp;gt;springmvc.xml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;mvc:annotation-driven&amp;gt;&amp;lt;/mvc:annotation-driven&amp;gt;
&amp;lt;context:component-scan base-package=&quot;com.Lei&quot;&amp;gt;&amp;lt;/context:component-scan&amp;gt;
&amp;lt;bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&amp;gt;
    &amp;lt;property name=&quot;prefix&quot; value=&quot;/&quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&quot;suffix&quot; value=&quot;.jsp&quot;&amp;gt;&amp;lt;/property&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注：改变的是扫描的base-package下面的包包&lt;/p&gt;
&lt;h3&gt;6.controller层&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public class UserController {
    @Controller
    @RequestMapping(&quot;/user&quot;)
    public static class UserHandler {
        @Autowired
        private UserService userService;
        @GetMapping(&quot;/findAll&quot;)
        public ModelAndView findAll() {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName(&quot;index&quot;);
            modelAndView.addObject(&quot;list&quot;, userService.findAll());
            return modelAndView;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.view视图&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&amp;gt;
&amp;lt;%@ page isELIgnored=&quot;false&quot; %&amp;gt;
&amp;lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Title&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;c:forEach items=&quot;${list}&quot; var=&quot;user&quot;&amp;gt;
    ${user.id}--${user.name}--${user.score}&amp;lt;br/&amp;gt;
&amp;lt;/c:forEach&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6.注释&lt;/h3&gt;
&lt;p&gt;对于不同的层存在不同的注释&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;dao层不需要添加注释&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;service层中对于impl实现类需要添加&lt;code&gt;@Service&lt;/code&gt;注释，并且要将dao层自动装配&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Autowired
private UserDao userDao;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;controller层中首先就是&lt;code&gt;@Controller&lt;/code&gt;注释表明是controller层并且可以自动扫描；其次就是对于不同的实现方法需要进行不一样的位置跳转，需要requestMapping或者是getMapping还有servlet&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Autowired
private UserService userService;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7.常见错&lt;/h3&gt;
&lt;p&gt;对于sqlFactory的报错，一般是因为sqlFacotry扫描到的包不止一个&lt;/p&gt;
&lt;p&gt;对于无法依赖数据库我这边出现的错误还是因为c3p0，版本原因，可以换高版本，还有对于jdbc的连接出错&lt;/p&gt;
&lt;h3&gt;7.总要概括&lt;/h3&gt;
&lt;p&gt;需要改动的部分只有&lt;/p&gt;
&lt;p&gt;spring.xml中的两个bean，分别用来读取datasource数据源，对应mapper位置以及mybatis信息的配置，还有另一个bean是用来扫描自定义接口&lt;/p&gt;
&lt;p&gt;springmvc.xml中的base-package&lt;/p&gt;
&lt;p&gt;jdbc连接的url：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=true&amp;amp;useUnicode=true&amp;amp;characterEncoding=utf8&amp;amp;serverTimezone=Asia/Shanghai
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>前端结构设计</title><link>https://210214.xyz/posts/frontend-structure/</link><guid isPermaLink="true">https://210214.xyz/posts/frontend-structure/</guid><description>前端开发查漏补缺，包含浮动、display、选择器、盒子模型、定位等知识点</description><pubDate>Sun, 21 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前端查漏补缺&lt;/h2&gt;
&lt;h3&gt;1.元素浮动：&lt;/h3&gt;
&lt;p&gt;对于块级元素，可以通过设置元素的float形式让其进行浮动，将其排放在一行，方便布局，但是同样的会造成父级元素的塌陷。采用下面的代码进行清除浮动。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.clearFixed::after {
    content: &quot;&quot;;
    display: block;
    clear: both;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过一个伪类选择器来进行元素的添加，谁需要清除浮动就给它设置这个属性&lt;/p&gt;
&lt;p&gt;解释：after表示放在元素的后面，并且必须要写内容，这个是通过伪类选择的，默认是行元素，只有block的元素进行clear才会有效，&lt;code&gt;clear:both&lt;/code&gt;是将左右两边的浮动都清除掉&lt;/p&gt;
&lt;h3&gt;2. display&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:none&lt;/code&gt; -&amp;gt;隐藏。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:inline&lt;/code&gt; -&amp;gt;设置为行级元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:block&lt;/code&gt;-&amp;gt;设置为块级元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:inline-block&lt;/code&gt;设置行级块元素&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;行级元素&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;多个元素占一行&lt;/li&gt;
&lt;li&gt;不能设置宽高&lt;/li&gt;
&lt;li&gt;eg.&lt;code&gt;span``a&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;块级元素(&lt;code&gt;p&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;自己占一行&lt;/li&gt;
&lt;li&gt;可以设置宽高&lt;/li&gt;
&lt;li&gt;eg.&lt;code&gt;div``p``h1-h6``ul li``table&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;行级块元素&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;多个元素占一行&lt;/li&gt;
&lt;li&gt;可以设置宽高&lt;/li&gt;
&lt;li&gt;eg.&lt;code&gt;img``input``button&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;visibility:hidden&lt;/code&gt;-&amp;gt;元素不可见，但是占据宽高&lt;/p&gt;
&lt;h3&gt;3.选择器&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;子代选择器&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;语法 ：&lt;code&gt;选择器 &amp;gt; 选择器&lt;/code&gt; 表示第一个选择器的第一个子代，再往后面就选不了&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;相邻兄弟选择器&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;语法 ：&lt;code&gt;选择器 + 选择器&lt;/code&gt;表示只选择第一个选择器的下面一个紧邻的选择器&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;伪类选择器&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:hover&lt;/code&gt; 当鼠标滑入的时候有效果(&lt;strong&gt;最常用&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:link&lt;/code&gt; 当没有访问过的时候产生效果&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:visited&lt;/code&gt; 点击了后访问过产生效果&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:active&lt;/code&gt; 激活，当你鼠标点在这个标签上，没有离开时候的效果&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;伪元素选择器&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;::after&lt;/code&gt; 在选择的标签的最后插上新的内容(&lt;strong&gt;行级元素&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;::before&lt;/code&gt; 在选择的标签的最前面插上新的内容(&lt;strong&gt;行级元素&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;注&lt;/strong&gt;：但是after和before元素是必须要加上content属性，可以给空&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;属性选择器&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;语法： 标签/属性 &lt;code&gt;[属性名]  \[属性名 == &apos;某属性值&apos;]&lt;/code&gt; 表示选择标签/属性下的属性为什么的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;a&quot;&amp;gt;
    &amp;lt;div id=&quot;id&quot;&amp;gt;
        你好
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;div[id] {
    background: pink;
}
div[id =&apos;id&apos;] {
    background: pink;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.img三像素问题&lt;/h3&gt;
&lt;p&gt;导致原因：&lt;code&gt;img&lt;/code&gt;的display默认值&lt;code&gt;inline-block&lt;/code&gt;导致&lt;/p&gt;
&lt;p&gt;解决：设置&lt;code&gt;display：block&lt;/code&gt;;&lt;/p&gt;
&lt;h3&gt;5.盒子模型&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Css&lt;/code&gt; 盒子模型： 内容+padding+border +margin&lt;/p&gt;
&lt;p&gt;层级：内容-&amp;gt;padding -&amp;gt;border -&amp;gt; margin&lt;/p&gt;
&lt;p&gt;&lt;code&gt;width&lt;/code&gt; 属性：就是内容的宽度&lt;/p&gt;
&lt;p&gt;对于属性的设置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以单独对每个top left right bottom设置&lt;/li&gt;
&lt;li&gt;给一个值：每个边的都是等距的&lt;/li&gt;
&lt;li&gt;给两个值：垂直 水平分别设置&lt;/li&gt;
&lt;li&gt;给四个值：上右下左，顺时针方向&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.定位&lt;/h3&gt;
&lt;p&gt;position字段&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;relative&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;相对于自己初始的位置&lt;/li&gt;
&lt;li&gt;定位后空间不释放&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;absolute&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;位置相对于自己已经定位的祖先元素，一直找到最上层body&lt;/li&gt;
&lt;li&gt;定位空间释放&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;fixed固定定位(一般的广告就是)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;位置相对可视页面&lt;/li&gt;
&lt;li&gt;定位后空间释放&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7.实现文字的省略号效果&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.选择器 {
    overflow: hidden;
    text-overflow:ellipsis;
    white-space: nowrap;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8.nth-of-type&lt;/h3&gt;
&lt;p&gt;正常选用nth-of-type不用nth-of-child&lt;/p&gt;
&lt;p&gt;并且可以通过公式来全选&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#使用公式 (an + b)。描述：表示周期的长度，n 是计数器（从 0 开始），b 是偏移值。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;9.首行缩进&lt;/h3&gt;
&lt;p&gt;text-indent:缩进段落的第一行&lt;/p&gt;
</content:encoded></item><item><title>Css布局模式</title><link>https://210214.xyz/posts/css-layout/</link><guid isPermaLink="true">https://210214.xyz/posts/css-layout/</guid><description>Flex布局和Grid布局详解</description><pubDate>Mon, 01 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;[toc]&lt;/p&gt;
&lt;h3&gt;1.flex布局&lt;/h3&gt;
&lt;p&gt;含义：Flex 是 Flexible Box 的缩写，意为&quot;弹性布局&quot;，用来为盒状模型提供最大的灵活性。&lt;/p&gt;
&lt;p&gt;特点：任何一个容器都可以指定为 Flex 布局。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box{
    display: flex;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;作用：它的所有子元素自动成为容器成员，称为 Flex 项目&lt;/p&gt;
&lt;h4&gt;1.1容器属性&lt;/h4&gt;
&lt;h5&gt;1.1.1flex-direction&lt;/h5&gt;
&lt;p&gt;表示主轴方向,有四种选项&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;row(默认) 从左向右排列，水平方向主轴&lt;/p&gt;
&lt;p&gt;row-reverse 从右向左，水平方向主轴&lt;/p&gt;
&lt;p&gt;column 从上往下，竖直方向主轴&lt;/p&gt;
&lt;p&gt;column-reverse 从下往上，竖直方向为主轴&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;1.1.2flex-wrap&lt;/h5&gt;
&lt;p&gt;如果本来的容器大小不够本元素放就会需要换行，但是默认不会换行&lt;/p&gt;
&lt;p&gt;例：将原来的box容器width改成200,显然这个时候宽度不够放。默认就是nowrap不换行&lt;/p&gt;
&lt;p&gt;而定义了flex-wrap:wrap属性后就会换行（这里为了美观将容器的width改成了100px）&lt;/p&gt;
&lt;h5&gt;1.1.3justify-content(重要)&lt;/h5&gt;
&lt;p&gt;属性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;flex-start(默认):相当于就是左对齐&lt;/p&gt;
&lt;p&gt;flex-end：右对齐&lt;/p&gt;
&lt;p&gt;center：中间对齐&lt;/p&gt;
&lt;p&gt;space-between（常用）：左边的靠左，右边的靠右，中间的居中&lt;/p&gt;
&lt;p&gt;spcae-evenly：中间分配相等的空余空间&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;justify-content: center&lt;/li&gt;
&lt;li&gt;justify-content: space-between&lt;/li&gt;
&lt;li&gt;justify-content: space-evenly&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;1.1.4align-items&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;align-items&lt;/code&gt;属性定义项目在交叉轴上如何对齐。(单根主轴的对齐)&lt;/p&gt;
&lt;p&gt;属性&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;flex-start：交叉轴的起点对齐。&lt;/p&gt;
&lt;p&gt;flex-end：交叉轴的终点对齐。&lt;/p&gt;
&lt;p&gt;center交叉轴的中点对齐。&lt;/p&gt;
&lt;p&gt;baseline: 项目的第一行文字的基线对齐。&lt;/p&gt;
&lt;p&gt;stretch（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;align-items:flex-end&lt;/li&gt;
&lt;li&gt;align-items:center&lt;/li&gt;
&lt;li&gt;align-items:stretch(这个是将第一个元素的高度取消了固定值)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;1.1.5 align-content(多根主轴的对其方式)&lt;/h5&gt;
&lt;p&gt;如果没有设置这个属性，当元素多了之后的效果&lt;/p&gt;
&lt;p&gt;属性：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;flex-start：交叉轴的起点对齐。&lt;/p&gt;
&lt;p&gt;flex-end：交叉轴的终点对齐。&lt;/p&gt;
&lt;p&gt;center交叉轴的中点对齐。&lt;/p&gt;
&lt;p&gt;baseline: 项目的第一行文字的基线对齐。&lt;/p&gt;
&lt;p&gt;stretch（默认值）：如果项目未设置高度或设为auto，将占满整个容器的高度。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;1.2 flex项目&lt;/h4&gt;
&lt;p&gt;以下6个属性设置在项目上。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;order&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex-grow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex-shrink&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex-basis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;align-self&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;1.2.1 order&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;order&lt;/code&gt;属性定义项目的排列顺序。数值越小，排列越靠前，默认为0。&lt;/p&gt;
&lt;p&gt;关于这个不是很实用，对应的元素顺序一般该在哪就放哪里去，别整花里胡哨&lt;/p&gt;
&lt;h5&gt;1.2.2 flex-grow&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;flex-grow&lt;/code&gt;属性定义项目的放大比例，默认为&lt;code&gt;0&lt;/code&gt;，即如果存在剩余空间，也不放大。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.two {flex-grow: 1;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参与比例分配，如果只是一个分配，就是直接按100%；&lt;/p&gt;
&lt;p&gt;用途：用于处理横向的分布式布局十分好用&lt;/p&gt;
&lt;h5&gt;1.2.3 flex-shrink属性&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;flex-shrink&lt;/code&gt;属性定义了项目的缩小比例，默认为1，即如果空间不足，该项目将缩小。&lt;/p&gt;
&lt;p&gt;按比例收缩，不是很必要，要么换行就好，不同的元素多收缩容易出现比例很难调&lt;/p&gt;
&lt;h5&gt;1.2.4 align-self&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;align-self&lt;/code&gt;属性允许单个项目有与其他项目不一样的对齐方式，可覆盖&lt;code&gt;align-items&lt;/code&gt;属性。默认值为&lt;code&gt;auto&lt;/code&gt;，表示继承父元素的&lt;code&gt;align-items&lt;/code&gt;属性，如果没有父元素，则等同于&lt;code&gt;stretch&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;很少见：就相当于是只有一个特殊的需要调整&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.two {flex-grow: 1;
    align-self: flex-end;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;1.3flex实战小样-九宫格&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;Title&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }
        .redpackage {
            width: 300px;
            height: 300px;
            outline: 1px solid black;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            align-content: space-between;
        }
        .redpackage div {
            width: 33%;
            height: 33%;
            background: #e1544a;
            font-size: 32px;
            display: flex;
            justify-content: center;
            align-items: center;
            text-align: center;
            outline: 1px solid white;
            position: relative;
            z-index: 0;
        }
        .redpackage div:after {
            position: absolute;
            content: &quot;&quot;;
            display: block;
            width: 80%;
            height: 80%;
            background: #ddbd84;
            border-radius: 50%;
            z-index: -1;
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div class=&quot;redpackage&quot;&amp;gt;
    &amp;lt;div&amp;gt;你&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;有&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;一&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;个&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;红&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;包&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;未&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;取&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.grid布局&lt;/h3&gt;
&lt;p&gt;注：设为网格布局以后，容器子元素（项目）的&lt;code&gt;float&lt;/code&gt;、&lt;code&gt;display: inline-block&lt;/code&gt;、&lt;code&gt;display: table-cell&lt;/code&gt;、&lt;code&gt;vertical-align&lt;/code&gt;和&lt;code&gt;column-*&lt;/code&gt;等设置都将失效。&lt;/p&gt;
&lt;h4&gt;2.1容器属性&lt;/h4&gt;
&lt;h5&gt;2.1.1grid-template-*&lt;/h5&gt;
&lt;h6&gt;设置网格&lt;/h6&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px 100px;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;简便写法：效果是一样的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns:repeat(3,100px);
grid-template-rows: repeat(4,100px);
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;auto-fill&lt;/h6&gt;
&lt;p&gt;auto-fill,有时，单元格的大小是固定的，但是容器的大小不确定，这个属性就会自动填充&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns:repeat(auto-fill,100px);
grid-template-rows: repeat(auto-fill,100px);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;基本就是自动填充，可以根据屏幕的长度拉伸&lt;/p&gt;
&lt;h6&gt;fr&lt;/h6&gt;
&lt;p&gt;为了方便比例关系，这个是grid模型提供的关键字&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns:repeat(3,1 fr);
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;minmax()&lt;/h6&gt;
&lt;p&gt;&lt;code&gt;minmax()&lt;/code&gt;函数产生一个长度范围，表示长度就在这个范围之中。它接受两个参数，分别为最小值和最大值。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns: 1 fr 1 fr minmax(100px, 1 fr);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面代码中，&lt;code&gt;minmax(100px, 1fr)&lt;/code&gt;表示列宽不小于&lt;code&gt;100px&lt;/code&gt;，不大于&lt;code&gt;1fr&lt;/code&gt;。&lt;/p&gt;
&lt;h6&gt;auto&lt;/h6&gt;
&lt;p&gt;可以自动分配，跟flex模型的flex-grow有点像，但是更好用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-columns:100px auto 100px;
grid-template-rows: repeat(auto-fill,100px);
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.1.2gap&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;项目相互之间的距离&lt;/p&gt;
&lt;p&gt;row-gap:行距&lt;/p&gt;
&lt;p&gt;column-gap:宽距&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;row-gap: 20px;
column-gap: 20px;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.1.3area&lt;/h5&gt;
&lt;p&gt;一个区域由单个或多个单元格组成，由你决定（具体使用，需要在项目属性里面设置）&lt;/p&gt;
&lt;p&gt;设置区域：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-areas: &apos;a b c&apos; &apos;d e f&apos; &apos;g h i&apos;;
grid-template-areas: &apos;a a a&apos; &apos;b b b&apos; &apos;c c c&apos;;
grid-template-areas: &apos;a . c&apos; &apos;b . f&apos; &apos;g . i&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.1.4 auto-flow&lt;/h5&gt;
&lt;p&gt;grid-auto-flow&lt;/p&gt;
&lt;p&gt;划分网格以后，容器的子元素会按照顺序，自动放置在每一个网格。默认的放置顺序是&quot;先行后列&quot;，&lt;/p&gt;
&lt;p&gt;即先填满第一行，再开始放入第二行（就是子元素的排放顺序）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;row(默认) 按照行排列&lt;/p&gt;
&lt;p&gt;column 按照列排&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;2.1.5对其方式justify(重要)&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;justify-items（水平）：容器内每一个元素的对其&lt;/p&gt;
&lt;p&gt;align-items(竖直)：网格内每一个元素对其&lt;/p&gt;
&lt;p&gt;justify-content：（水平）整个容器的对其&lt;/p&gt;
&lt;p&gt;align-content：（竖直）整个容器的对其&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;2.2项目属性&lt;/h4&gt;
&lt;h5&gt;2.2.1 grid-column/row-start/end&lt;/h5&gt;
&lt;p&gt;一句话解释：用来指定的items的具体位置，根据在哪根网格线&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;grid-column-start&lt;/code&gt;属性：左边框所在的垂直网格线&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grid-column-end&lt;/code&gt;属性：右边框所在的垂直网格线&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grid-row-start&lt;/code&gt;属性：上边框所在的水平网格线&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grid-row-end&lt;/code&gt;属性：下边框所在的水平网格线&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;.item-1 {
    background-color: #ef342a;
    grid-column-start: 1;
    grid-column-end: 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;简化写法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.item-1 {
    background-color: #ef342a;
    grid-column: 1/3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.2.2 grid-area&lt;/h5&gt;
&lt;p&gt;可以根据area改变区域&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.item-1 {
    background-color: #ef342a;
    grid-column: 1/3;
    grid-area: b;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2.2.3justify-self(相当于一个个例)&lt;/h5&gt;
&lt;p&gt;用法和flex浮动一样&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;justify-self属性设置单元格内容的水平位置（左中右)，跟justify-items属性的用法完全一致，
但只作用于单个项目（水平方向）&lt;/p&gt;
&lt;p&gt;align-self属性设置单元格内容的垂直位置（上中下)，跟align–items)属性的用法完全一致，
也是只作用于单个项目（垂直方向）&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Spring2 框架入门</title><link>https://210214.xyz/posts/spring2-framework/</link><guid isPermaLink="true">https://210214.xyz/posts/spring2-framework/</guid><description>Spring框架IoC和AOP详解</description><pubDate>Mon, 01 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Spring&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;IoC（控制反转）/ DI（依赖注入）&lt;/li&gt;
&lt;li&gt;AOP（面向切面编程）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.创建IOC工程&lt;/h3&gt;
&lt;h4&gt;1.1导入依赖&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.0.11.RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.18.24&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IOC框架只需要context依赖就够了&lt;/p&gt;
&lt;h4&gt;1.2创建实体类&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;public class Student {
    private long id;
    private String name;
    private int age;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;1.3编写对应的配置文件，Spring.xml(全局）&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xmlns:p=&quot;http://www.springframework.org/schema/p&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
       &quot;&amp;gt;
    &amp;lt;bean id=&quot;student&quot; class=&quot;com.Lei.pojo.Student&quot;&amp;gt;
        &amp;lt;property name=&quot;id&quot; value=&quot;0&quot;&amp;gt;&amp;lt;/property&amp;gt;
        &amp;lt;property name=&quot;name&quot; value=&quot;张三&quot;&amp;gt;&amp;lt;/property&amp;gt;
        &amp;lt;property name=&quot;age&quot; value=&quot;10&quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;/bean&amp;gt;
&amp;lt;/beans&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;上面的beans是文件头，黏贴就好，然后下面的bean就是写自己的对应的实体类
&lt;ul&gt;
&lt;li&gt;bean标签依据id来对应你需要创建的实体类，需要通过class指定好对应的实体类的路径&lt;/li&gt;
&lt;li&gt;下面的&lt;code&gt;property&lt;/code&gt;就是为值附的属性，如果没有就是默认的结果&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;1.4主程序调试&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) {
    ApplicationContext applicationContext =new ClassPathXmlApplicationContext(&quot;Spring.xml&quot;);

    Student student = (Student) applicationContext.getBean(&quot;student&quot;);

    System.out.println(student);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.配置文件&lt;/h3&gt;
&lt;h4&gt;2.1标准&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;通过配置 &lt;code&gt;bean&lt;/code&gt; 标签来完成对象的管理。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt;：对象名。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;class&lt;/code&gt;：对象的模版类（所有交给 IoC 容器来管理的类必须有无参构造函数，因为 Spring 底层是通过反射机制来创建对象，调用的是无参构造）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对象的成员变量通过 &lt;code&gt;property&lt;/code&gt; 标签完成赋值。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;：成员变量名。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;：成员变量值（基本数据类型，String 可以直接赋值，如果是其他引用类型，不能通过 value 赋值）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref&lt;/code&gt;：将 IoC 中的另外一个 bean 赋给当前的成员变量（DI）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.模拟IOC底层&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;思路&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;解析xml配置文件&lt;/li&gt;
&lt;li&gt;得到里面的元素，遍历获取对应的id、class路径&lt;/li&gt;
&lt;li&gt;用类解析反射出整个类，获取构造器，创建对象&lt;/li&gt;
&lt;li&gt;通过Map键值对存储获取的id和整个类对象&lt;/li&gt;
&lt;li&gt;getBean方法就是通过id来取Map中的对象&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4.bean的调用&lt;/h3&gt;
&lt;h4&gt;4.1通过运行时类获取 bean&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;ApplicationContext applicationContext = new ClassPathXmlApplicationContext(&quot;spring.xml&quot;);
Student student = (Student) applicationContext.getBean(Student.class);
System.out.println(student);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式存在一个问题，配置文件中一个数据类型的对象只能有一个实例，否则会抛出异常，因为没有唯一的 bean。还是推荐直接用id获取bean；&lt;/p&gt;
&lt;h4&gt;4.2通过有参构造创建 bean&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;在实体类中创建对应的有参构造函数。&lt;/li&gt;
&lt;li&gt;三种方式，推荐下面第一个，如果不写name或者index就需要按对应顺序写&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;bean id=&quot;student3&quot; class=&quot;com.Lei.pojo.Student&quot;&amp;gt;
    &amp;lt;constructor-arg name=&quot;id&quot; value=&quot;3&quot;&amp;gt;&amp;lt;/constructor-arg&amp;gt;
    &amp;lt;constructor-arg name=&quot;name&quot; value=&quot;小明&quot;&amp;gt;&amp;lt;/constructor-arg&amp;gt;
    &amp;lt;constructor-arg name=&quot;age&quot; value=&quot;18&quot;&amp;gt;&amp;lt;/constructor-arg&amp;gt;
    &amp;lt;constructor-arg name=&quot;address&quot; ref=&quot;address&quot;&amp;gt;&amp;lt;/constructor-arg&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4.3给bean注入集合&lt;/h4&gt;
&lt;h3&gt;5.作用域&lt;/h3&gt;
&lt;p&gt;Spring 管理的 bean 是根据 scope 来生成的，表示 bean 的作用域，共4种，默认值是 singleton。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;singleton：单例，表示通过 IoC 容器获取的 bean 是唯一的。&lt;/li&gt;
&lt;li&gt;prototype：原型，表示通过 IoC 容器获取的 bean 是不同的。&lt;/li&gt;
&lt;li&gt;request：请求，表示在一次 HTTP 请求内有效。&lt;/li&gt;
&lt;li&gt;session：回话，表示在一个用户会话内有效。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;request 和 session 只适用于 Web 项目，大多数情况下，使用单例和原型较多。&lt;/p&gt;
&lt;h3&gt;6.Spring继承&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;与 Java 的继承不同，Java 是类层面的继承，子类可以继承父类的内部结构信息；Spring 是对象层面的继承，子对象可以继承父对象的属性值。&lt;/li&gt;
&lt;li&gt;Spring 的继承关注点在于具体的对象，而不在于类，即不同的两个类的实例化对象可以完成继承，前提是子对象必须包含父对象的所有属性，同时可以在此基础上添加其他的属性。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h3&gt;7.Spring依赖&lt;/h3&gt;
&lt;p&gt;与继承类似，依赖也是描述 bean 和 bean 之间的一种关系，配置依赖之后，被依赖的 bean 一定先创建，再创建依赖的 bean，A 依赖于 B，先创建 B，再创建 A。&lt;/p&gt;
&lt;h3&gt;8.Spring 的 p 命名空间&lt;/h3&gt;
&lt;p&gt;p 命名空间是对 IoC / DI 的简化操作，使用 p 命名空间可以更加方便的完成 bean 的配置以及 bean 之间的依赖注入。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;bean id=&quot;student&quot; class=&quot;com.southwind.entity.Student&quot; p:id=&quot;1&quot; p:name=&quot;张三&quot; p:age=&quot;22&quot; p:address-ref=&quot;address&quot;&amp;gt;&amp;lt;/bean&amp;gt;
&amp;lt;bean id=&quot;address&quot; class=&quot;com.southwind.entity.Address&quot; p:id=&quot;2&quot; p:name=&quot;科技路&quot;&amp;gt;&amp;lt;/bean&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其实和property一样，简化写法&lt;/p&gt;
&lt;h3&gt;9.Spring工厂&lt;/h3&gt;
&lt;p&gt;IoC 通过工厂模式创建 bean 的方式有两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;静态工厂&lt;/li&gt;
&lt;li&gt;实例工厂&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;10.IoC 自动装载（Autowire）&lt;/h3&gt;
&lt;p&gt;IoC 负责创建对象，DI 负责完成对象的依赖注入，通过配置 property 标签的 ref 属性来完成，同时 Spring 提供了另外一种更加简便的依赖注入方式：自动装载，不需要手动配置 property，IoC 容器会自动选择 bean 完成注入。自动装载有两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;byName：通过属性名自动装载，找实体类中属性名与bean中对应的id&lt;/li&gt;
&lt;li&gt;byType：通过属性的数据类型自动装载,找同一致的数据类型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;byType 需要注意，如果同时存在两个及以上的符合条件的 bean 时，自动装载会抛出异常。&lt;/p&gt;
&lt;h3&gt;11.Aop切面&lt;/h3&gt;
&lt;p&gt;AOP：Aspect Oriented Programming 面向切面编程。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AOP 的优点：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;降低模块之间的耦合度。&lt;/li&gt;
&lt;li&gt;使系统更容易扩展。&lt;/li&gt;
&lt;li&gt;更好的代码复用。&lt;/li&gt;
&lt;li&gt;非业务代码更加集中，不分散，便于统一管理。&lt;/li&gt;
&lt;li&gt;业务代码更加简洁存粹，不参杂其他代码的影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AOP 是对面向对象编程的一个补充，在运行时，动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面编程。将不同方法的同一个位置抽象成一个切面对象，对该切面对象进行编程就是 AOP。&lt;/p&gt;
</content:encoded></item><item><title>css入门</title><link>https://210214.xyz/posts/css-intro/</link><guid isPermaLink="true">https://210214.xyz/posts/css-intro/</guid><description>CSS基础知识入门，包含选择器、样式美化、盒子模型等</description><pubDate>Thu, 21 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Css&lt;/h2&gt;
&lt;h3&gt;优先级&lt;/h3&gt;
&lt;p&gt;内嵌样式优先级是最高的，后面外联和行内看定义时候的就近原则&lt;/p&gt;
&lt;p&gt;补充：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;块级元素：要分段的&lt;/li&gt;
&lt;li&gt;行内元素：不要分段的&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;选择器（重点）&lt;/h3&gt;
&lt;h4&gt;1.基本选择器&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;标签选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;选了之后，所有这个标签就是统一的样式，太死了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    标签{
        ;
        ;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;类选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可跨，方便&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    .类名{
        ;
        ;
        ;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;id选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;id只能有一个，有点局限&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
    #id名{
        ;
        ;
        ;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优先级：id选择器 &amp;gt; class选择器 &amp;gt; 标签选择器，不遵循就近原则&lt;/p&gt;
&lt;h4&gt;2.层次选择器&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;后代选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在某个元素的后面，这一代的后面所有&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*后代选择器*/
body 标签名{
    ;
    ;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;子选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在这个元素的后面，但是只有后面一代&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 子代选择器 */
body&amp;gt;标签名{
    ;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;相邻兄弟选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;选择这一代的下一个，不能隔着东西&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.类名 +下面的一个标签{
    ;
    ;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;通用选择器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个类的下面的所有这个标签&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.类名~下面的标签{
    ;
    ;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.结构伪类选择器&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;标签:&lt;/code&gt; 的形式，用来过滤一些条件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ul li:first-child {
    /* 选择ul标签下的li标签中第一个元素 */
    background-color: blue;
}
ul li:last-child{
    /* 选择ul标签下的li标签中最后一个元素 */
    color: red;
}
p:nth-of-type(x){
    /* p的上级标签下面选择p标签的第x个 */
    background-color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4.属性选择器&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt; 绝对等于&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*=&lt;/code&gt; 包含&lt;/li&gt;
&lt;li&gt;&lt;code&gt;^=&lt;/code&gt; 以这个符号开头&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$=&lt;/code&gt; 以这个符号结尾&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a[herf^=http]/*选择a标签中的herf属性开头是http*/
/*标签[属性/id/class 表达式]*/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;样式美化&lt;/h3&gt;
&lt;h4&gt;1.字体样式&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;/*
font-family:字体
font-size:字体大小
font-weight:字体粗细
color:字体颜色
*/
body{
    font-family:&quot;Arial Black&quot;,楷体;
    color:#a13d30;
}
h1{
    font-size: 50px;
}
.p1{
    font-weight:bolder;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2.文本样式&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;/* 颜色 color rgb rgba
   文本对齐的方式 text-align=center
   首行缩进 text-indent:2em;
   行高 line-height
   装饰 text-decoration-&amp;gt;删除a标签的下划线
   文本图片水平对齐 vertical-align:middle
*/
p {
    color: brown;
    text-align: center;
    text-indent: 2em;
    line-height: 2em;
}
a {
    text-decoration: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.超链接伪类&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;/*超连接伪类，还有阴影*/
a {
    text-decoration: none;
    color: black;
}
/* 鼠标悬浮颜色,也只要记住这个 */
a:hover {
    color: orange;
    font-size: 30px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4.阴影效果&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;/* text-shadow: 阴影颜色，水平偏移，垂直偏移，阴影半径 */
p {
    text-shadow: #3cc7f5 10px -10px 2px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;盒子模型&lt;/h3&gt;
&lt;p&gt;所谓&lt;strong&gt;盒子模型&lt;/strong&gt;就是把HTML页面中的元素看作是一个矩形的盒子，也就是一个盛装内容的容器。每个矩形都是由元素的内容（content）、内边距（padding）、边框（border）和外边距（margin）组成。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;margin:外边距&lt;/li&gt;
&lt;li&gt;padding:内边距&lt;/li&gt;
&lt;li&gt;border:边框&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.box {
    width: 200px;
    height: 100px;
    padding: 20px;
    box-sizing: border-box;
    background-color: blue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;盒子的大小=外边距+内边距+边框+内容&lt;/p&gt;
</content:encoded></item><item><title>springmvc框架入门</title><link>https://210214.xyz/posts/springmvc-intro/</link><guid isPermaLink="true">https://210214.xyz/posts/springmvc-intro/</guid><description>Spring MVC框架入门教程，包含核心组件、数据绑定、REST风格等</description><pubDate>Sun, 17 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;SpringMvc&lt;/h2&gt;
&lt;p&gt;Spring MVC 是目前主流的实现 MVC 设计模式的企业级开发框架，Spring 框架的一个子模块，无需整合，开发起来更加便捷。&lt;/p&gt;
&lt;h2&gt;1.SpringMvc核心思想&lt;/h2&gt;
&lt;h3&gt;1.1 Spring MVC 的核心组件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;DispatcherServlet：前置控制器，是整个流程控制的核心，控制其他组件的执行，进行统一调度，降低组件之间的耦合性，相当于总指挥。&lt;/li&gt;
&lt;li&gt;Handler：处理器，完成具体的业务逻辑，相当于 Servlet 或 Action。&lt;/li&gt;
&lt;li&gt;HandlerMapping：DispatcherServlet 接收到请求之后，通过 HandlerMapping 将不同的请求映射到不同的 Handler。&lt;/li&gt;
&lt;li&gt;HandlerInterceptor：处理器拦截器，是一个接口，如果需要完成一些拦截处理，可以实现该接口。&lt;/li&gt;
&lt;li&gt;HandlerExecutionChain：处理器执行链，包括两部分内容：Handler 和 HandlerInterceptor。&lt;/li&gt;
&lt;li&gt;HandlerAdapter：处理器适配器，Handler 执行业务方法之前，需要进行一系列的操作。&lt;/li&gt;
&lt;li&gt;ModelAndView：装载了模型数据和视图信息，作为 Handler 的处理结果，返回给 DispatcherServlet。&lt;/li&gt;
&lt;li&gt;ViewResolver：视图解析器，DispatcheServlet 通过它将逻辑视图解析为物理视图。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.2 Spring MVC 的工作流程&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;客户端请求被 DisptacherServlet 接收。&lt;/li&gt;
&lt;li&gt;根据 HandlerMapping 映射到 Handler。&lt;/li&gt;
&lt;li&gt;生成 Handler 和 HandlerInterceptor。&lt;/li&gt;
&lt;li&gt;Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一并返回给 DisptacherServlet。&lt;/li&gt;
&lt;li&gt;DispatcherServlet 通过 HandlerAdapter 调用 Handler 的方法完成业务逻辑处理。&lt;/li&gt;
&lt;li&gt;Handler 返回一个 ModelAndView 给 DispatcherServlet。&lt;/li&gt;
&lt;li&gt;DispatcherServlet 将获取的 ModelAndView 对象传给 ViewResolver 视图解析器。&lt;/li&gt;
&lt;li&gt;ViewResovler 返回一个 View 给 DispatcherServlet。&lt;/li&gt;
&lt;li&gt;DispatcherServlet 根据 View 进行视图渲染。&lt;/li&gt;
&lt;li&gt;DispatcherServlet 将渲染后的结果响应给客户端。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2.创建一个SpringMvc工程&lt;/h2&gt;
&lt;h3&gt;2.1 导入依赖&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-webmvc&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.0.11.RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-aop&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.0.11.RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-aspects&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.0.11.RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;5.0.11.RELEASE&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.2 配置springmvc的xml文件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xmlns:mvc=&quot;http://www.springframework.org/schema/mvc&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd&quot;&amp;gt;
    &amp;lt;context:component-scan base-package=&quot;com.Lei&quot;&amp;gt;&amp;lt;/context:component-scan&amp;gt;
    &amp;lt;bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&amp;gt;
        &amp;lt;property name=&quot;prefix&quot; value=&quot;/&quot;&amp;gt;&amp;lt;/property&amp;gt;
        &amp;lt;property name=&quot;suffix&quot; value=&quot;.jsp&quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;/bean&amp;gt;
&amp;lt;/beans&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.3 编写web.xml注册springmvc的servlet&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
        &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
        &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;
&amp;lt;web-app&amp;gt;
    &amp;lt;servlet&amp;gt;
        &amp;lt;servlet-name&amp;gt;DispatcherServlet&amp;lt;/servlet-name&amp;gt;
        &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;
        &amp;lt;init-param&amp;gt;
            &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
            &amp;lt;param-value&amp;gt;classpath:springmvc.xml&amp;lt;/param-value&amp;gt;
        &amp;lt;/init-param&amp;gt;
    &amp;lt;/servlet&amp;gt;
    &amp;lt;servlet-mapping&amp;gt;
        &amp;lt;servlet-name&amp;gt;DispatcherServlet&amp;lt;/servlet-name&amp;gt;
        &amp;lt;url-pattern&amp;gt;/&amp;lt;/url-pattern&amp;gt;
    &amp;lt;/servlet-mapping&amp;gt;
&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.4 编写测试主程序&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@Controller
@RequestMapping(&quot;/hello&quot;)
public class HelloHandler {
    @RequestMapping(value = &quot;index&quot;,params = {&quot;name&quot;,&quot;id&quot;})
    public String index(String name,int id){
        System.out.println(name);
        System.out.println(id);
        return &quot;index&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.Spring MVC 注解&lt;/h2&gt;
&lt;h3&gt;@RequestMapping&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;value：指定 URL 请求的实际地址&lt;/li&gt;
&lt;li&gt;method：指定请求的 method 类型，GET、POST、PUT、DELETE&lt;/li&gt;
&lt;li&gt;params：指定请求中必须包含某些参数&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(value = &quot;/index&quot;,method = RequestMethod.GET,params = {&quot;name&quot;,&quot;id=10&quot;})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;@Controller&lt;/h3&gt;
&lt;p&gt;在类定义处添加，将该类交给 IoC 容器来管理&lt;/p&gt;
&lt;h2&gt;4.Spring MVC 数据绑定&lt;/h2&gt;
&lt;h3&gt;4.1 基本数据类型&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(&quot;/baseType&quot;)
@ResponseBody
public String baseType(int id){
    return id+&quot;&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 包装类&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(&quot;/packageType&quot;)
@ResponseBody
public String packageType(@RequestParam(value = &quot;num&quot;,required = false,defaultValue = &quot;0&quot;) Integer id){
    return id+&quot;&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.3 数组&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/data&quot;)
public class DataBindHandler {
    @RequestMapping(&quot;/array&quot;)
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.Spring MVC 模型数据解析&lt;/h2&gt;
&lt;h3&gt;5.1 Map&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(&quot;/map&quot;)
public String map(Map&amp;lt;String, User&amp;gt; map){
    User user = new User();
    user.setId(6);
    user.setName(&quot;老六&quot;);
    map.put(&quot;user&quot;,user);
    return &quot;view&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.2 Model&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(&quot;/model&quot;)
public String model(Model model){
    User user = new User();
    user.setId(6);
    user.setName(&quot;老六&quot;);
    model.addAttribute(&quot;user&quot;,user);
    return &quot;view&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.3 ModelAndView（重要）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(&quot;/modelandview&quot;)
public ModelAndView modelAndView(){
    User user = new User();
    user.setId(6);
    user.setName(&quot;老六&quot;);
    ModelAndView modelAndView = new ModelAndView(&quot;view&quot;);
    modelAndView.addObject(&quot;user&quot;,user);
    return modelAndView;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.REST风格&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;GET 用来表示获取资源&lt;/li&gt;
&lt;li&gt;POST 用来表示新建资源&lt;/li&gt;
&lt;li&gt;PUT 用来表示修改资源&lt;/li&gt;
&lt;li&gt;DELETE 用来表示删除资源&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.文件上传下载&lt;/h2&gt;
&lt;h3&gt;7.1 单文件上传&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@Controller
@RequestMapping(&quot;/file&quot;)
public class fileHandler {
    @RequestMapping(&quot;/upload&quot;)
    public String upload(MultipartFile img, HttpServletRequest request) throws IOException {
        String filename = img.getOriginalFilename();
        String path = request.getServletContext().getRealPath(&quot;file&quot;);
        File file = new File(path,filename);
        img.transferTo(file);
        String newPath =&quot;/file/&quot;+filename;
        request.getSession().setAttribute(&quot;path&quot;, newPath);
        return &quot;upload&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.2 多文件上传&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@RequestMapping(&quot;/uploads&quot;)
public String uploads(MultipartFile[] imgs, HttpServletRequest request) throws IOException {
    List&amp;lt;String&amp;gt; files = new ArrayList&amp;lt;&amp;gt;();
    for (MultipartFile img : imgs) {
        String filename = img.getOriginalFilename();
        String path = request.getServletContext().getRealPath(&quot;file&quot;);
        File file = new File(path, filename);
        img.transferTo(file);
        files.add(&quot;/file/&quot; + filename);
    }
    request.getSession().setAttribute(&quot;paths&quot;, files);
    return &quot;uploads&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.SpringMvc表单后台校验&lt;/h2&gt;
&lt;h3&gt;8.1 Validator接口&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public class AccountValidator implements Validator {
    @Override
    public boolean supports(Class&amp;lt;?&amp;gt; aClass) {
        return Account.class.equals(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors,&quot;name&quot;,null,&quot;用户名不能为空&quot;);
        ValidationUtils.rejectIfEmpty(errors,&quot;password&quot;,null,&quot;密码不能为空&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8.2 Annotation JSR-303 标准&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;@Data
public class Person {
    @NotEmpty(message = &quot;用户名不能为空&quot;)
    private String username;
    @Size(min = 6, max = 12, message = &quot;密码6-12位&quot;)
    private String password;
    @Email(regexp = &quot;^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$&quot;, message = &quot;请输入正确的邮箱格式&quot;)
    private String email;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;常用注解&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;注释名&lt;/th&gt;
&lt;th&gt;效果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;@Null&lt;/td&gt;
&lt;td&gt;被注解的元素必须为null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@NotNull&lt;/td&gt;
&lt;td&gt;被注解的元素不能为null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@Min(value)&lt;/td&gt;
&lt;td&gt;被注解的元素必须是一个数字，其值必须大于等于指定的最小值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@Max(value)&lt;/td&gt;
&lt;td&gt;被注解的元素必须是一个数字，其值必须小于等于指定的最大值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@Email&lt;/td&gt;
&lt;td&gt;被注解的元素必须是电子邮箱地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@Pattern&lt;/td&gt;
&lt;td&gt;被注解的元素必须符合对应的正则表达式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@Length&lt;/td&gt;
&lt;td&gt;被注解的元素的大小必须在指定的范围内&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@NotEmpty&lt;/td&gt;
&lt;td&gt;被注解的字符串的值必须非空&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>java 注释与反射</title><link>https://210214.xyz/posts/java-annotation-reflection/</link><guid isPermaLink="true">https://210214.xyz/posts/java-annotation-reflection/</guid><description>Java注解与反射机制学习笔记</description><pubDate>Fri, 15 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;注解&lt;/h2&gt;
&lt;h3&gt;1. Annotation&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;注解不是程序本身，但是可以对程序做出解释&lt;/li&gt;
&lt;li&gt;注解可以被其他程序（比如：编译器）读取&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2. 元注解&lt;/h3&gt;
&lt;p&gt;元注解的作用就是负责注解其他注解，Java定义了4个标准的meta-annotation类型，他们被用来提供对其他annotation类型作说明：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Target：描述注解的使用位置&lt;/li&gt;
&lt;li&gt;Retention：描述注解的生命周期，表示在什么级别保存该注解的信息（3个取值：SOURCE&amp;lt;CLASS&amp;lt;RUNTIME）&lt;/li&gt;
&lt;li&gt;Document：说明该注解可以被生成在Javadoc中&lt;/li&gt;
&lt;li&gt;Inherited：说明子类可以继承父类中的该注解&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3. 自定义注解&lt;/h3&gt;
&lt;p&gt;使用@interface自定义注解时，自动继承了&lt;code&gt;java.lang.annotation.Annotation&lt;/code&gt;接口&lt;/p&gt;
&lt;p&gt;分析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;@interface用来声明一个注解，格式：public @interface 注解名{定义内容}&lt;/li&gt;
&lt;li&gt;其中的每一个方法实际上是声明了一个配置参数&lt;/li&gt;
&lt;li&gt;方法的名称就是参数的名称&lt;/li&gt;
&lt;li&gt;返回值类型就是参数的类型（返回值只能是基本类型，Class, String, enum）&lt;/li&gt;
&lt;li&gt;可以通过default来声明参数的默认值&lt;/li&gt;
&lt;li&gt;如果只有一个参数成员，一般参数名为value&lt;/li&gt;
&lt;li&gt;注解元素必须要有值，我们定义注解元素时，经常使用空字符串，0作为默认值&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DiyAnnotation {
    String name();
    int age() default 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// 获取方法上的自定义注解
public class ServiceImpl {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class&amp;lt;?&amp;gt; aClass = Class.forName(&quot;com.hxxy.service.ServiceImpl&quot;);
        Method method = aClass.getDeclaredMethod(&quot;method&quot;, Integer.class);
        DiyAnnotation declaredAnnotation = method.getDeclaredAnnotation(DiyAnnotation.class);
        System.out.println(declaredAnnotation);
    }

    @DiyAnnotation(name = &quot;annotation&quot;)
    public String method(Integer a){
        System.out.println(&quot;method:&quot; + a);
        return &quot;a&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;反射&lt;/h2&gt;
&lt;h3&gt;1. 反射概述&lt;/h3&gt;
&lt;p&gt;反射就是Reflection，Java的反射是指程序在运行期可以拿到一个对象的所有信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reflection(反射)是Java被视为动态语言的关键，反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息，并能直接操作任意对象的内部属性及方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Class c = Class.forName(&quot;java.lang.String&quot;) // 获取String包里的所有东西
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正常方式：引入需要的&quot;包类&quot;名称 -&amp;gt; 通过new实例化 -&amp;gt; 取得实例化对象&lt;/p&gt;
&lt;p&gt;反射方式：实例化对象 -&amp;gt; getClass()方法 -&amp;gt; 得到完整的&quot;包类&quot;名称&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;优点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以实现动态创建对象和编译，体现出很大的灵活性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对性能有影响。使用反射基本上是一种解释操作，我们可以告诉JVM我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 反射的常用方法&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法名&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;static Class forName(String name)&lt;/td&gt;
&lt;td&gt;返回指定类名name的Class对象&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object newInstance()&lt;/td&gt;
&lt;td&gt;调用缺省构造函数，返回Class对象的一个实例&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;getName()&lt;/td&gt;
&lt;td&gt;返回此Class对象所表示的实体（类，接口，数组类或void)的名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class getSuperClass()&lt;/td&gt;
&lt;td&gt;返回当前Class对象的父类的Class对象&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class[] getInterfaces()&lt;/td&gt;
&lt;td&gt;获取当前Class对象的接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ClassLoader getClassLoader()&lt;/td&gt;
&lt;td&gt;返回该类的类加载器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constructor[] getConstructors()&lt;/td&gt;
&lt;td&gt;返回一个包含某些Constructor对象的数组&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method getMethod(String name, Class...T)&lt;/td&gt;
&lt;td&gt;返回一个Method对象，此对象的形参类型为paramType&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Field[] getDeclaredFields()&lt;/td&gt;
&lt;td&gt;返回Field对象的一个数组&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. 获取反射对象&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;若已知具体的类，通过类的class属性获取，该方法最为安全可靠，程序性能最高。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Class clazz = Person.class;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;已知某个类的实例，调用该实例的getClass()方法获取Class对象&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Class clazz = Person.getClass();
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;已知一个类的全类名，且该类在类路径下，可通过Class类的静态方法forName()获取，可能抛出ClassNotFoundException&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Class clazz = Class.forName(&quot;demo01.Student&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 反射出来的对象的应用&lt;/h3&gt;
&lt;p&gt;先获取反射的对象，可以同该对象调用很多其方法，获取构造函数，获取字段(属性)，方法……&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class User {
    private String name;
    private int id;
    private int age;
    //还有一些公有的get,set方法和一个无参构造和有参构造+tostring的重写
    ...
}

//测试类
public static void main(String[] args) {
    Class c1 = Class.forName(&quot;Reflection.Demo01.User&quot;); // 通过forname获取类的对象
    User user = (User) c1.newInstance(); // 构造一个对象
    System.out.println(user.getAge()); // 通过该对象调用方法

    Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); // 通过类对象获取有参构造函数
    Object xixi = constructor.newInstance(&quot;xixi&quot;, 001, 18); // 通过有参构造创建新对象
    System.out.println(xixi);

    User user01 = (User) c1.newInstance();
    Method setName = c1.getDeclaredMethod(&quot;setName&quot;, String.class); // 通过类对象获取方法字段
    setName.invoke(user01, &quot;haha&quot;); // 方法需要激活invoke方法，然后传入参数（使用的对象，传入实参）
    System.out.println(user01);

    User user02 = (User) c1.newInstance();
    Field name = c1.getDeclaredField(&quot;name&quot;); // 通过类对象获取字段
    name.setAccessible(true); // 如果字段是私有不可访问的时候需要开启这个权限才能访问字段的值
    name.set(user02, &quot;none&quot;); // name字段设置值-&amp;gt;(使用的对象，传入的实参)
    System.out.println(user02.getName());
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>mybatis入门</title><link>https://210214.xyz/posts/mybatis-intro/</link><guid isPermaLink="true">https://210214.xyz/posts/mybatis-intro/</guid><description>MyBatis框架入门教程，包含配置、CRUD操作、级联查询、逆向工程等</description><pubDate>Thu, 14 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;MyBatis&lt;/h2&gt;
&lt;p&gt;MyBatis重要核心步骤：省去了建表，写对应的实体类(可以用lombok组件)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//对应实体类
public class Account {
    private long id;
    private String username;
    private String password;
    private int age;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;1.创建 MyBatis 的配置文件 config.xml&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE configuration PUBLIC &quot;-//mybatis.org//DTD Config 3.0//EN&quot; &quot;http://mybatis.org/dtd/mybatis-3-config.dtd&quot;&amp;gt;
&amp;lt;configuration&amp;gt;
    &amp;lt;environments default=&quot;account&quot;&amp;gt;
        &amp;lt;environment id=&quot;account&quot;&amp;gt;
            &amp;lt;transactionManager type=&quot;JDBC&quot;&amp;gt;&amp;lt;/transactionManager&amp;gt;
            &amp;lt;dataSource type=&quot;POOLED&quot;&amp;gt;
                &amp;lt;property name=&quot;driver&quot; value=&quot;com.mysql.cj.jdbc.Driver&quot;/&amp;gt;
                &amp;lt;property name=&quot;url&quot; value=&quot;jdbc:mysql://localhost:3306/mybatis01?useUnicode=true&amp;amp;characterEncoding=UTF-8&quot;/&amp;gt;
                &amp;lt;property name=&quot;username&quot; value=&quot;111&quot;/&amp;gt;
                &amp;lt;property name=&quot;password&quot; value=&quot;111&quot;/&amp;gt;
            &amp;lt;/dataSource&amp;gt;
        &amp;lt;/environment&amp;gt;
    &amp;lt;/environments&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.通过原生接口实现&lt;/h2&gt;
&lt;h3&gt;2.1 Mapper.xml的编写&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt;
&amp;lt;!DOCTYPE mapper PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot; &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&amp;gt;
&amp;lt;mapper namespace=&quot;Account.Account&quot;&amp;gt;
    &amp;lt;insert id=&quot;save&quot; parameterType=&quot;Account.Account&quot;&amp;gt;
        insert into account (username ,password,age) values (#{username},#{password},#{age});
    &amp;lt;/insert&amp;gt;
&amp;lt;/mapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.2 注册mapper.xml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;mappers&amp;gt;
    &amp;lt;mapper resource=&quot;AccountConfig/Mapper.xml&quot;&amp;gt;&amp;lt;/mapper&amp;gt;
&amp;lt;/mappers&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.3 调用API&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public class Test01 {
    public static void main(String[] args) {
        InputStream inputStream =Test01.class.getResourceAsStream(&quot;/config.xml&quot;);
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = build.openSession();
        Account account = new Account(1L,&quot;张三&quot;,&quot;root&quot;,24);
        String statement =&quot;Account.Account.save&quot;;
        sqlSession.insert(statement,account);
        sqlSession.commit();
        sqlSession.close();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.自定义接口实现(推荐)&lt;/h2&gt;
&lt;h3&gt;3.1 编写接口&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public interface AccountRepository {
    public int save(Account account);
    public int update (Account account);
    public int deleteById(long id);
    public List&amp;lt;Account&amp;gt; findAll();
    public Account findById(long id);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 创建对应的xml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt;
&amp;lt;!DOCTYPE mapper PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot; &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&amp;gt;
&amp;lt;mapper namespace=&quot;AccountRepository.AccountRepository&quot;&amp;gt;
    &amp;lt;insert id=&quot;save&quot; parameterType=&quot;Account.Account&quot;&amp;gt;
        insert into account (username, password, age) values (#{username}, #{password}, #{age});
    &amp;lt;/insert&amp;gt;
    &amp;lt;update id=&quot;update&quot; parameterType=&quot;Account.Account&quot;&amp;gt;
        update account set username =#{username},password =#{password},age =#{age} where id = #{id};
    &amp;lt;/update&amp;gt;
    &amp;lt;delete id=&quot;deleteById&quot; parameterType=&quot;long&quot;&amp;gt;
        delete from account where id = #{id};
    &amp;lt;/delete&amp;gt;
    &amp;lt;select id=&quot;findAll&quot; resultType=&quot;Account.Account&quot;&amp;gt;
        select * from account;
    &amp;lt;/select&amp;gt;
    &amp;lt;select id=&quot;findById&quot; resultType=&quot;Account.Account&quot;&amp;gt;
        select * from account where id = #{id};
    &amp;lt;/select&amp;gt;
&amp;lt;/mapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.3 调用API&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) {
    InputStream resourceAsStream = Test02.class.getClassLoader().getResourceAsStream(&quot;config.xml&quot;);
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
    SqlSession sqlSession = build.openSession();
    AccountRepository mapper = sqlSession.getMapper(AccountRepository.class);
    for (Account account : mapper.findAll()) {
        System.out.println(account);
    }
    sqlSession.commit();
    sqlSession.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.级联查询&lt;/h2&gt;
&lt;h3&gt;4.1 一对多&lt;/h3&gt;
&lt;p&gt;通过学生查班级和学生&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;resultMap id=&quot;StudentMap&quot; type=&quot;com.Student.Student&quot;&amp;gt;
    &amp;lt;id column=&quot;id&quot; property=&quot;id&quot;&amp;gt;&amp;lt;/id&amp;gt;
    &amp;lt;result column=&quot;name&quot; property=&quot;name&quot;&amp;gt;&amp;lt;/result&amp;gt;
    &amp;lt;association property=&quot;classes&quot; javaType=&quot;com.Student.Classes&quot;&amp;gt;
        &amp;lt;id column=&quot;cid&quot; property=&quot;id&quot;&amp;gt;&amp;lt;/id&amp;gt;
        &amp;lt;result column=&quot;cname&quot; property=&quot;name&quot;&amp;gt;&amp;lt;/result&amp;gt;
    &amp;lt;/association&amp;gt;
&amp;lt;/resultMap&amp;gt;
&amp;lt;select id=&quot;findById&quot; parameterType=&quot;long&quot; resultMap=&quot;StudentMap&quot;&amp;gt;
    select s.id ,s.name,c.id cid,c.name cname from student s,classes c where s.id = #{id} and c.id =cid;
&amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 多对一&lt;/h3&gt;
&lt;p&gt;通过班级类查询学生&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;resultMap id=&quot;ClassesMap&quot; type=&quot;com.Student.Classes&quot;&amp;gt;
    &amp;lt;id column=&quot;id&quot; property=&quot;id&quot;&amp;gt;&amp;lt;/id&amp;gt;
    &amp;lt;result column=&quot;name&quot; property=&quot;name&quot;&amp;gt;&amp;lt;/result&amp;gt;
    &amp;lt;collection property=&quot;students&quot; ofType=&quot;com.Student.Student&quot;&amp;gt;
        &amp;lt;id column=&quot;sid&quot; property=&quot;id&quot;&amp;gt;&amp;lt;/id&amp;gt;
        &amp;lt;result column=&quot;sname&quot; property=&quot;name&quot;&amp;gt;&amp;lt;/result&amp;gt;
    &amp;lt;/collection&amp;gt;
&amp;lt;/resultMap&amp;gt;
&amp;lt;select id=&quot;findById&quot; parameterType=&quot;long&quot; resultMap=&quot;ClassesMap&quot;&amp;gt;
    select s.id sid,s.name sname,c.id,c.name from student s, classes c where c.id =#{id} and cid =c.id;
&amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.逆向工程&lt;/h2&gt;
&lt;h3&gt;5.1 导入依赖&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mybatis.generator&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mybatis-generator-core&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.4.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.2 创建配置文件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE generatorConfiguration
        PUBLIC &quot;-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN&quot;
        &quot;http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd&quot;&amp;gt;
&amp;lt;generatorConfiguration&amp;gt;
    &amp;lt;context id=&quot;testTables&quot; targetRuntime=&quot;MyBatis3&quot;&amp;gt;
        &amp;lt;jdbcConnection driverClass=&quot;com.mysql.cj.jdbc.Driver&quot;
                        connectionURL=&quot;jdbc:mysql://localhost:3306/mybatis01?useUnicode=true&amp;amp;characterEncoding=UTF-8&quot;
                        userId=&quot;root&quot;
                        password=&quot;root&quot;&amp;gt;
        &amp;lt;/jdbcConnection&amp;gt;
        &amp;lt;javaModelGenerator targetPackage=&quot;com.Lei.pojo&quot; targetProject=&quot;./src/main/java&quot;&amp;gt;&amp;lt;/javaModelGenerator&amp;gt;
        &amp;lt;sqlMapGenerator targetPackage=&quot;com.Lei.mapper&quot; targetProject=&quot;./src/main/java&quot;&amp;gt;&amp;lt;/sqlMapGenerator&amp;gt;
        &amp;lt;javaClientGenerator type=&quot;XMLMAPPER&quot; targetPackage=&quot;com.Lei.mapper&quot;
                             targetProject=&quot;./src/main/java&quot;&amp;gt;&amp;lt;/javaClientGenerator&amp;gt;
        &amp;lt;table tableName=&quot;student&quot; domainObjectName=&quot;Student&quot;&amp;gt;&amp;lt;/table&amp;gt;
    &amp;lt;/context&amp;gt;
&amp;lt;/generatorConfiguration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.延迟加载&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;settings&amp;gt;
    &amp;lt;!-- 打印SQL执行的语句--&amp;gt;
    &amp;lt;setting name=&quot;logImpl&quot; value=&quot;STDOUT_LOGGING&quot;/&amp;gt;
    &amp;lt;!-- 开启延迟加载--&amp;gt;
    &amp;lt;setting name=&quot;lazyLoadingEnabled&quot; value=&quot;true&quot;/&amp;gt;
&amp;lt;/settings&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.MyBatis缓存&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;一级缓存：SqlSession 级别，默认开启，不能关闭。&lt;/li&gt;
&lt;li&gt;二级缓存：Mapper 级别，默认关闭，可以开启。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;settings&amp;gt;
    &amp;lt;!-- 开启二级缓存 --&amp;gt;
    &amp;lt;setting name=&quot;cacheEnabled&quot; value=&quot;true&quot;/&amp;gt;
&amp;lt;/settings&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.动态SQL&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;标签名&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;if&lt;/td&gt;
&lt;td&gt;根据表达式的结果来决定是否将对应的语句添加到 SQL 中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;where&lt;/td&gt;
&lt;td&gt;自动判断是否要删除语句块中的 and 关键字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;choose when&lt;/td&gt;
&lt;td&gt;类似于if和where的连用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trim&lt;/td&gt;
&lt;td&gt;自动删除语句前后的指定值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;set&lt;/td&gt;
&lt;td&gt;用于 update 操作，会自动根据参数选择生成 SQL 语句&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;foreach&lt;/td&gt;
&lt;td&gt;迭代生成一系列值，主要用于 SQL 的 in 语句&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;select id=&quot;findByAccount&quot; resultType=&quot;com.Account.Account&quot; parameterType=&quot;com.Account.Account&quot;&amp;gt;
    select *from account
    &amp;lt;where&amp;gt;
        &amp;lt;if test=&quot;id!=0&quot;&amp;gt; and id= #{id}&amp;lt;/if&amp;gt;
        &amp;lt;if test=&quot;username!=null&quot;&amp;gt; and username = #{username}&amp;lt;/if&amp;gt;
        &amp;lt;if test=&quot;password&quot;&amp;gt; and password = #{password}&amp;lt;/if&amp;gt;
        &amp;lt;if test=&quot;age!=0&quot;&amp;gt; and age = #{age}&amp;lt;/if&amp;gt;
    &amp;lt;/where&amp;gt;
&amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>javaweb</title><link>https://210214.xyz/posts/javaweb/</link><guid isPermaLink="true">https://210214.xyz/posts/javaweb/</guid><description>JavaWeb开发基础知识整理</description><pubDate>Wed, 06 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1.编写Servlet&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;重要补充：request是从服务器获取数据，response是从服务器向浏览器返回数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过配置的maven新建&lt;code&gt;webapp&lt;/code&gt;模板工程并且配置pom.xml文件(是mvn的核心文件)来导入Servlet的依赖&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;javax.servlet-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.1.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;创建一个类继承HttpServlet，并重写Service方法&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    res.getWriter().write(&quot;Hello servlet&quot;);//通过浏览器窗口输出Hello servlet
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;在web.xml里编写映射&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;web-app xmlns=&quot;http://xmlns.jcp.org/xml/ns/javaee&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd&quot;
         version=&quot;3.1&quot;
         metadata-complete=&quot;true&quot;&amp;gt;
&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.ServletContext&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;解释：每一个web应用都有且仅有一个ServletContext对象，又称Application对象，从名称中可知，该对象是与应用程序相关的。在WEB容器启动的时候，会为每一个WEB应用程序创个对应的ServletContext对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;作用：&lt;strong&gt;共享数据&lt;/strong&gt;，可以通过一方来保存，另一方可以读取&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;两个小方法：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;getServletContext//设置储存的信息，以键值对的形式
getAttribute//获取储存的信息，需要键的名为对象
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.请求转发&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;不改变原来的地址，但是能够改变跳转的位置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;ServletContext context = this.getServletContext();//先获取context对象
context.getRequestDispatcher(&quot;/cf&quot;).forward(req,resp);//调用getRequestDispatcher方法输入请求转发的地址
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.通过Servletcontext读取配置文件&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    Properties prop = new Properties();
    InputStream ras = context.getResourceAsStream(&quot;/WEB-INF/classes/db.properties&quot;);
    prop.load(ras);
    String username = prop.getProperty(&quot;username&quot;);
    String pwd = prop.getProperty(&quot;password&quot;);
    resp.getWriter().write(username+&quot;:&quot;+pwd);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.Response&lt;/h2&gt;
&lt;h3&gt;5.1 下载&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String realPath = &quot;D:\\project\\java\\execrise\\project02\\src\\main\\resources\\a.jpg&quot;;
    String fileName = realPath.substring(realPath.lastIndexOf(&quot;\\&quot;) + 1);
    resp.setHeader(&quot;Content-Disposition&quot;, &quot;attachment;filename=&quot; +fileName );//最重要的设置头，表明下载
    FileInputStream fis = new FileInputStream(realPath);
    ServletOutputStream os = resp.getOutputStream();//获取流去读写
    byte[] buffer = new byte[1024];
    int len ;
    while((len = fis.read(buffer))!=-1){
        os.write(len);
    }
    os.close();
    fis.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.2 重定向&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public class Demo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect(&quot;/cf/demo03&quot;);//重定向的地址
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.Request&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public class Demo06 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;进入了这个服务&quot;);
        String username = req.getParameter(&quot;username&quot;);//获取username信息
        String password = req.getParameter(&quot;password&quot;);//获取password信息
        System.out.println(username+&quot;:&quot;+password);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7.Cookies&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType(&quot;text/html;charset = utf-8&quot;);//设置服务器返回编码
    Cookie[] cookies = req.getCookies();//先获取cookies
    PrintWriter writer = resp.getWriter();//浏览器输出
    boolean flag =false;
    for (Cookie cookie : cookies) {
        if (cookie.getName().equals(&quot;lastTime&quot;)){
            Long timer = Long.valueOf(cookie.getValue());//还原原来的日期格式
            Date date = new Date(timer);
            SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);//设置日期格式
            String currentTime = sdf.format(date);
            writer.write(&quot;你上一次访问本站的时间是:&quot;+currentTime);
            flag =true;
        }
    }
    if (!flag)   writer.write(&quot;这是你第一次访问,我们为您创建了cookie，方便下次访问&quot;);
    Cookie lastTime = new Cookie(&quot;lastTime&quot;, System.currentTimeMillis() + &quot;&quot;);//Cookie都是以键值对的形式存在
    resp.addCookie(lastTime);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8.Session&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding(&quot;utf-8&quot;);
    resp.setContentType(&quot;text/html;charset = utf-8&quot;);
    HttpSession session = req.getSession();
    session.setAttribute(&quot;username&quot;, new Person(&quot;借口&quot;,18));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9.JSP&lt;/h2&gt;
&lt;h3&gt;9.1 Jsp语法&lt;/h3&gt;
&lt;p&gt;整个JSP的内容实际上是一个HTML，但是稍有不同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;包含在&lt;code&gt;&amp;lt;%--&lt;/code&gt;和&lt;code&gt;--%&amp;gt;&lt;/code&gt;之间的是JSP的注释；&lt;/li&gt;
&lt;li&gt;包含在&lt;code&gt;&amp;lt;%&lt;/code&gt;和&lt;code&gt;%&amp;gt;&lt;/code&gt;之间的是Java代码，可以编写任意Java代码；&lt;/li&gt;
&lt;li&gt;如果使用&lt;code&gt;&amp;lt;%= xxx %&amp;gt;&lt;/code&gt;则可以快捷输出一个变量的值。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;%! %&amp;gt;&lt;/code&gt;可以写java代码（作用域更高的，相当于全局），称之为声明&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;9.2 内置9大对象&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;PageContext        //存东西，级别最次
Request            //存东西，级别次
Response
Session            //存东西，级别中
Application-&amp;gt;SerlvetContext  //存东西，级别高
config-&amp;gt;SerlvetConfig
out
page
exception
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10.Filter过滤器&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public class FilterDemo01 implements Filter {
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding(&quot;utf-8&quot;);//请求编码
        servletResponse.setContentType(&quot;text/html;charset = utf-8&quot;);//响应编码
        System.out.println(&quot;doFilter进入前面&quot;);
        filterChain.doFilter(servletRequest,servletResponse);//主要方法，看成一条链，传递原来的req和resp对象
        System.out.println(&quot;doFilter进入后面&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11.Listener&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public void sessionCreated(HttpSessionEvent se) {//创建方法
    ServletContext context = se.getSession().getServletContext();
    Integer onlineCnt = (Integer) context.getAttribute(&quot;onlineCnt&quot;);//获取onlineCnt的字段
    if (onlineCnt==null){
        onlineCnt= 1;
    }else {
        onlineCnt = onlineCnt+1;
    }
    context.setAttribute(&quot;onlineCnt&quot;,onlineCnt);//每次添加这字段
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12.JDBC&lt;/h2&gt;
&lt;h3&gt;12.1 配置信息&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;String url = &quot;jdbc:mysql://localhost:3306/test01?useUnicode=true&amp;amp;characterEncoding=UTF-8&amp;amp;serverTimezone=UTC&quot;;
String username = &quot;root&quot;;
String password = &quot;root&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12.2 加载驱动&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;) ;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12.3 连接数据库&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Connection connection = DriverManager.getConnection(url, username, password);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12.4 向数据库发送statement请求，CRUD&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Statement statement = connection.createStatement();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12.5 写sql&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;String sql =&quot;select *from person&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12.6 执行sql&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ResultSet res = statement.executeQuery(sql);
while (res.next()){
    System.out.println(&quot;id：&quot;+ res.getObject(&quot;id&quot;));
    System.out.println(&quot;name：&quot;+ res.getObject(&quot;name&quot;));
    System.out.println(&quot;password：&quot;+ res.getObject(&quot;password&quot;));
    System.out.println(&quot;email：&quot;+ res.getObject(&quot;email&quot;));
    System.out.println(&quot;birthday：&quot;+ res.getObject(&quot;birthday&quot;));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12.7 关闭连接&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;res.close();
statement.close();
connection.close();
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>jdbc连接</title><link>https://210214.xyz/posts/jdbc-connection/</link><guid isPermaLink="true">https://210214.xyz/posts/jdbc-connection/</guid><description>JDBC连接数据库的完整流程和具体实现</description><pubDate>Fri, 01 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;jdbc的连接过程&lt;/h2&gt;
&lt;h3&gt;1.加载JDBC驱动程序：&lt;/h3&gt;
&lt;h3&gt;2.提供JDBC连接的URL&lt;/h3&gt;
&lt;h3&gt;3.创建数据库的连接&lt;/h3&gt;
&lt;h3&gt;4.创建一个Statement&lt;/h3&gt;
&lt;h3&gt;5.执行SQL语句&lt;/h3&gt;
&lt;h3&gt;6.处理结果&lt;/h3&gt;
&lt;h3&gt;7.关闭JDBC对象&lt;/h3&gt;
&lt;h2&gt;具体实现：&lt;/h2&gt;
&lt;h3&gt;1.加载JDBC驱动程序：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;//加载MySql的驱动类
Class.forName(&quot;com.mysql.jdbc.Driver&quot;) ;
//成功加载后，会将Driver类的实例注册到DriverManager类中。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.提供JDBC连接的URL&lt;/h3&gt;
&lt;p&gt;注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;连接URL定义了连接数据库时的协议、子协议、数据源标识。&lt;/li&gt;
&lt;li&gt;书写形式：协议：子协议：数据源标识&lt;/li&gt;
&lt;li&gt;协议：在JDBC中总是以jdbc开始&lt;/li&gt;
&lt;li&gt;子协议：是桥连接的驱动程序或是数据库管理系统名称。&lt;/li&gt;
&lt;li&gt;数据源标识：标记找到数据库来源的地址与连接端口。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;//利用mysql连接：
jdbc:mysql:
//localhost:3306/test?useUnicode=true&amp;amp;characterEncoding=gbk ;
// useUnicode=true：表示使用Unicode字符集。如果characterEncoding设置为
// gb2312或GBK，本参数必须设置为true 。characterEncoding=gbk：字符编码方式。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.创建数据库的连接&lt;/h3&gt;
&lt;p&gt;要连接数据库，需要向java.sql.DriverManager请求并获得Connection对象， 该对象就代表一个数据库的连接。&lt;/p&gt;
&lt;p&gt;使用DriverManagerget的Connectin(String url,String username,String password)方法传入指定的欲连接的数据库的路径、数据库的用户名和 密码来获得。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;//连接MySql数据库，用户名和密码都是root
String url = &quot;jdbc:mysql://localhost:3306/test&quot; ;
String username = &quot;root&quot; ;
String password = &quot;root&quot; ;
Connection con =DriverManager.getConnection(url , username , password ) ;
System.out.println(&quot;数据库连接失败！&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.创建一个Statement&lt;/h3&gt;
&lt;p&gt;要执行SQL语句，必须获得java.sql.Statement实例，Statement实例分为以下3种类型：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;执行静态SQL语句。通常通过Statement实例实现。&lt;/li&gt;
&lt;li&gt;执行动态SQL语句。通常通过PreparedStatement实例实现。&lt;/li&gt;
&lt;li&gt;执行数据库存储过程。通常通过CallableStatement实例实现。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具体实现方法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Statement stmt = con.createStatement() ;
PreparedStatement pstmt = con.prepareStatement(sql) ;
CallableStatement cstmt = con.prepareCall(&quot;{CALL demoSp(? , ?)}&quot;) ;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.执行SQL语句&lt;/h3&gt;
&lt;p&gt;Statement接口提供了三种执行SQL语句的方法：executeQuery、executeUpdate 和execute&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ResultSet executeQuery(String sqlString)：执行查询数据库的SQL语句返回一个结果集（ResultSet）对象。&lt;/li&gt;
&lt;li&gt;int executeUpdate(String sqlString)：用于执行INSERT、UPDATE或 DELETE语句以及SQL DDL语句&lt;/li&gt;
&lt;li&gt;execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的语句。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具体实现代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ResultSet rs = stmt.executeQuery(&quot;SELECT * FROM ...&quot;) ;
int rows = stmt.executeUpdate(&quot;INSERT INTO ...&quot;) ;
boolean flag = stmt.execute(String sql) ;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6.处理结果&lt;/h3&gt;
&lt;p&gt;两种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;执行更新返回的是本次操作影响到的记录数。&lt;/li&gt;
&lt;li&gt;执行查询返回的结果是一个ResultSet对象。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ResultSet包含符合SQL语句中条件的所有行，并且它通过一套get方法提供了对这些行中数据的访问。&lt;/p&gt;
&lt;p&gt;使用结果集（ResultSet）对象的访问方法获取数据：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while(rs.next()){
    String name = rs.getString(&quot;name&quot;) ;
    String pass = rs.getString(1) ; // 此方法比较高效
}
//（列是从左到右编号的，并且从列1开始）
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.关闭JDBC对象&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;关闭记录集&lt;/li&gt;
&lt;li&gt;关闭声明&lt;/li&gt;
&lt;li&gt;关闭连接对象&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>网络编程</title><link>https://210214.xyz/posts/java-network-programming/</link><guid isPermaLink="true">https://210214.xyz/posts/java-network-programming/</guid><description>Java网络编程学习笔记</description><pubDate>Fri, 24 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;网路编程&lt;/p&gt;
&lt;p&gt;&lt;code&gt;javaweb&lt;/code&gt;: 网页编程 B/S&lt;/p&gt;
&lt;p&gt;网络编程：&lt;code&gt;TCP/IP&lt;/code&gt; C/S&lt;/p&gt;
&lt;h3&gt;1. 如何实现网络通信&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通信双方的地址
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;端口号&lt;/li&gt;
&lt;li&gt;规则：网络通信协议
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TCP/IP&lt;/code&gt;参考模型&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. IP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;唯一定位一台网络上计算机&lt;/li&gt;
&lt;li&gt;127.0.0.1: 本机&lt;code&gt;localhost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip&lt;/code&gt;地址：&lt;code&gt;InetAddress&lt;/code&gt;类&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;InetAddress inetAddress = InetAddress.getByName(&quot;www.baidu.com&quot;); // 因为没有构造方法，只能通过调用他的静态方法直接获取一个他的属性
inetAddress.getHostAddress(); // ip
inetAddress.getHostName(); // 域名
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 端口&lt;/h3&gt;
&lt;p&gt;端口表示计算机上的一个程序的进程；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同的进程有不同的端口号！用来区分软件！&lt;/li&gt;
&lt;li&gt;端口分类：
&lt;ul&gt;
&lt;li&gt;公有端口 0~1023&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTTP&lt;/code&gt;: 80&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTTPS&lt;/code&gt;: 443&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FTP&lt;/code&gt;: 21&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Telent&lt;/code&gt;: 23&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;程序注册端口：1024~49151，分配用户或者程序
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Tomcat&lt;/code&gt;: 8080&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MySQL&lt;/code&gt;: 3306&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Oracle&lt;/code&gt;: 1521&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常用dos端口命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;netstat -ano      # 查看所有的端口
netstat -ano|findstr &quot;5900&quot;  # 查看指定的端口号
tasklist|findstr &quot;8696&quot;      # 查看指定端口的进程
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;InetSocketAddress&lt;/code&gt;类：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;InetSocketAddress inetSocketAddress = new InetSocketAddress(&quot;hostname&quot;, port);
getHostName()  // 获取地址(如果有映射会变成地址的名称)
getAddress()   // 获取地址
getPort()      // 获取端口
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 通信协议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;协议&lt;/strong&gt;：就是约定；&lt;strong&gt;网络通信协议&lt;/strong&gt;：速率，传输码率，代码结构，传输控制...&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TCP/UDP&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TCP&lt;/code&gt;: 用户传输协议&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UDP&lt;/code&gt;: 用户数据报协议&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;出名的协议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IP&lt;/code&gt;: 网络互连协议&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TCP&lt;/code&gt;: 打电话(必须是双方都有回应)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连接，稳定&lt;/li&gt;
&lt;li&gt;&lt;code&gt;三次握手&lt;/code&gt; &lt;code&gt;四次挥手&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# 最少需要三次，保证稳定连接！
# 握手
A: 你瞅啥？
B: 瞅你咋地？
A: 干一场！

# 挥手
# 场景：面试官与你
A: 我要走了！
B: 你快走吧！
B: 赶紧滚hh
A: 我的真的要走了！
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;传输完成，释放连接，效率低&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;UDP&lt;/code&gt;: 发短信(只需要发了就行，管他收到收不到)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不连接，不稳定&lt;/li&gt;
&lt;li&gt;效率极高&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. TCP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;客户端&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;连接服务器Socket发送消息&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;建立服务的端口&lt;code&gt;ServerSocket&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;等待用户的链接 accept&lt;/li&gt;
&lt;li&gt;接收用的消息&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;模拟&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重点：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ServerSocket&lt;/code&gt; 创建服务器类&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Socket&lt;/code&gt; 套接字连接类&lt;/li&gt;
&lt;li&gt;io流输入和关闭&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public class TestClient { // 客户端
    public static void main(String[] args) throws IOException {
        InetAddress severIp = InetAddress.getByName(&quot;127.0.0.1&quot;);
        // 本客户端的ip地址
        int port = 9999;
        // 套接字连接的端口号
        Socket socket = new Socket(severIp, port);
        OutputStream os = socket.getOutputStream();
        // 通过io流向服务端传递信息
        os.write(&quot;你好&quot;.getBytes()); // IO流getBytes的使用
        socket.close(); // 关闭流
        os.close();
    }
}

public class TestServer { // 服务端
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9999);
        // 这里是服务器的端口等待客户端的消息
        Socket socket = serverSocket.accept();
        // 获取接收的消息
        InputStream is = socket.getInputStream();
        // 通过io流读取接收的消息
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 管道流
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer, 0, len);
        }
        System.out.println(baos.toString());
        baos.close(); // 关闭流
        is.close();
        socket.close();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;思路:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端需要一个ip地址和能接收的端口号，而服务端就需要创建这个端口号&lt;/li&gt;
&lt;li&gt;将客户端和服务端都用socket进行封装，如果服务端要接受东西&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;ServerSocket serverSocket = new ServerSocket(9999); // 创建9999的端口
Socket socket = serverSocket.accept(); // 接收东西通过套接字进行封装
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;剩下的都给&lt;code&gt;IO&lt;/code&gt;流：&lt;/p&gt;
&lt;p&gt;套路的&lt;code&gt;io&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 如果读入的是单纯的文字，就用字符流
// 如果读入的是图片，音频，等，就用字节流
// 管道流的化，如果对方传进来是什么类型，字符，字节，二进制，就用对应的管道流去接收
// 关于写入字符流套路
byte[] buffer = new byte[1024];
int len;
while ((len = 已经获取的字符流.read(buffer)) != -1) {
    新创建一个存储的地点.write(buffer, 0, len);
}
// 最后倒叙关闭流文件就行
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. UDP&lt;/h3&gt;
&lt;p&gt;实现&lt;code&gt;Udp&lt;/code&gt;连接：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调用DatagramSocket包，还是通过套接字进行传输，常用的两个方法, send和receive&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 发送端
public static void main(String[] args) throws IOException {
    DatagramSocket socket = new DatagramSocket(); // 通过DatagramSocket类库创建socket对象
    String name = &quot;你好，udp服务器&quot;;
    InetAddress localhost = InetAddress.getByName(&quot;localhost&quot;); // 获取域名地址
    DatagramPacket packet = new DatagramPacket(name.getBytes(), 0, name.getBytes().length, localhost, 9090);
    // 生成一个包裹需要几个参数，最后两个是域名地址和端口号，前面的是内容可以给根据需求改变
    socket.send(packet); // 调用send发送包
    socket.close(); // 关闭流
}

// 接收端，如果没有接受端，那么发送的包裹就会丢失
public static void main(String[] args) throws IOException {
    DatagramSocket socket = new DatagramSocket(9090); // 创建一个9090端口用于udp接收
    byte[] buffer = new byte[1024]; // 字节的读入
    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); // 这里不需要写端口号和域名，就像你收信息，只要收到就行；
    socket.receive(packet);
    System.out.println(new String(packet.getData())); // 输出包内的内容，由于是getData以字节返回所以通过新建String来输出
    socket.close(); // 关闭流
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实现两人聊天：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ChatSender { // 发送者
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(8888); // 配置用户端口和套接字
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // 监听键盘输入
        String s = reader.readLine(); // 将读入的变成字符串
        byte[] bytes = s.getBytes(); // 因为下面创建发送包需要的是字节数组，所以获取字节
        DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress(&quot;localhost&quot;, 6666)); // 获取发送包包
        socket.send(packet);
        socket.close();
    }
}

public class ChatReceiver { // 接收者
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(6666); // 配置另一位用户的端口和套接字
        while (true) { // 循环监听收包包
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length); // 获取数据包包
            socket.receive(packet);
            byte[] data = packet.getData();
            String s = new String(data, 0, data.length);
            System.out.println(s);
            if (s.equals(&quot;bye&quot;)) break;
        }
        socket.close();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. URL&lt;/h3&gt;
&lt;p&gt;https://www.baidu.com/ 就是地址url&lt;/p&gt;
&lt;p&gt;统一资源定位符：定位资源的，定位互联网上的某一个资源 DNS域名解析 www.baidu.com xxx.xxx...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 协议：//ip地址：端口/项目名/资源
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;URL url = new URL(&quot;http://www.baidu.com&quot;); // 新一个URL类
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); // openConnection建立连接
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>java 多线程</title><link>https://210214.xyz/posts/java-multithreading/</link><guid isPermaLink="true">https://210214.xyz/posts/java-multithreading/</guid><description>Java多线程编程学习笔记</description><pubDate>Thu, 23 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;多线程&lt;/h2&gt;
&lt;h3&gt;进程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在计算机中，我们把一个任务称为一个进程，浏览器就是一个进程，视频播放器是另一个进程，类似的，音乐播放器和Word都是进程。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进程和线程的关系：一个进程可以包含一个或多个线程，但至少会有一个线程。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;创建一个线程&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;方法一：&lt;/strong&gt; 继承Thread类，重写run()方法，调用start开启线程&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Demo04 extends Thread { // 继承Thread类
    @Override
    public void run() { // 重写run方法
        for (int i = 0; i &amp;lt; 5; i++) {
            System.out.println(&quot;线程里的方法：&quot; + i);
        }
    }

    public static void main(String[] args) {
        Demo04 demo04 = new Demo04();
        demo04.start(); // 用start方法开启线程
        // demo04.run(); // 这个就不会另外起一个线程
        System.out.println(&quot;主线程中的方法&quot;);
    }
    // start方法会产生主方法和另一个线程的方法同时执行，而直接调用run方法就会按原来顺序从上往下执行
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;方法二(推荐)：&lt;/strong&gt; 实现Runnable接口，创建线程对象，通过线程对象来开启我们的线程，代理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Demo05 implements Runnable { // 实现Runnable接口
    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 5; i++) {
            System.out.println(&quot;线程里的方法&quot; + i);
        }
    }

    public static void main(String[] args) {
        Demo05 demo05 = new Demo05(); // 创建线程对象
        new Thread(demo05).start(); // 通过线程对象来开启我们的线程
        // 重载方法：new Thread(实现Runnable接口的对象，线程的命名);
        System.out.println(&quot;主线程中的方法&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程并发&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;并发&lt;/strong&gt;：是指同一个时间段内多个任务同时都在执行，并且都没有执行结束。强调通过很小的时间片的切换对将程序交替执行，假象的并行效果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;并行&lt;/strong&gt;：两个以上事件（或线程）在同一时刻发生，没有时间片的交换，跑在不同的CPU资源上，一般是多核&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;抢票实例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Demo06 implements Runnable {
    private int TicketNum = 10; // 共同的抢票
    @Override
    public void run() {
        while (TicketNum &amp;gt; 0) {
            System.out.println(Thread.currentThread().getName() + &quot;抢到了第&quot; + (TicketNum--) + &quot;张票&quot;);
            // Thread.currentThread().getName()可以获取线程的名称;
        }
    }

    public static void main(String[] args) {
        Demo06 Ticket = new Demo06();
        new Thread(Ticket, &quot;1号线程&quot;).start();
        new Thread(Ticket, &quot;2号线程&quot;).start();
        new Thread(Ticket, &quot;3号线程&quot;).start();
    }
}
// 有可能会出现抢同一张票的情况
// 发现问题：多个线程操作同一个资源的情况下，线程不安全，数据紊乱
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;静态代理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;优点：可以在不修改目标对象的前提下&lt;strong&gt;扩展&lt;/strong&gt;目标对象的&lt;strong&gt;功能&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;操作步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先定义一个接口(有相应的方法)&lt;/li&gt;
&lt;li&gt;定义真实类和代理类，都要实现这个接口&lt;/li&gt;
&lt;li&gt;代理类中创建一个接口的属性，创建这个属性的构造函数&lt;/li&gt;
&lt;li&gt;主函数中代理类的构造函数传入一个实现接口的类/实例就可以实现代理的拓展功能&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public interface Marry { // 定义接口
    void HappyMarry(); // 接口中的方法
}

class You implements Marry { // 真实的类实现接口
    @Override
    public void HappyMarry() {
        System.out.println(&quot;终于结婚了&quot;);
    }
}

class WeddingHouse implements Marry { // 代理类，实现接口
    private Marry target; // 定义一个接口的属性
    public WeddingHouse(Marry target) {
        this.target = target;
    }
    @Override
    public void HappyMarry() {
        before(); // 对原来接口的扩充
        target.HappyMarry(); // 原来接口的方法
        after(); // 对原来接口的扩充
    }
    private void after() {
        System.out.println(&quot;处理后事&quot;);
    }
    private void before() {
        System.out.println(&quot;邀请嘉宾&quot;);
    }
}

// 主函数中实现
public static void main(String[] args) {
    // 第一种，直接创建一个代理类的对象，并且在构造函数中传入实现接口的真实对象
    WeddingHouse weddingHouse = new WeddingHouse(new You());
    weddingHouse.HappyMarry();

    // 第二种，直接调用隐士对象，就相当是new Thread(实现Runnable接口的对象).start();
    new WeddingHouse(new You()).HappyMarry();

    // 第三种，直接采用匿名内部类，直接进行输出代理拓展的内容
    new WeddingHouse(new Marry() {
        @Override
        public void HappyMarry() {
            System.out.println(&quot;我也要结婚啦&quot;); // 这里没有用真实的类，根据自己需求实现想要的功能
        }
    }).HappyMarry();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;lambda表达式&lt;/h3&gt;
&lt;p&gt;函数式接口的定义：&lt;/p&gt;
&lt;p&gt;任何接口，如果只包含唯一一个抽象方法，那么它就是一个函数式接口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface Runnable {
    public abstract void run();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于函数式接口，我们可以通过lambda表达式来创建该接口的对象。&lt;/p&gt;
&lt;p&gt;实现：创建一个类，实现接口，通过接口创建属性就可以新建一个实现接口类的对象，调用实现的方法，或者式lambda表达式&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface Love {
    void iLove();
}

class You implements Love { // 实现了接口
    @Override
    public void iLove() {
        System.out.println(&quot;i love you &quot;); // 重写方法
    }
}

public static void main(String[] args) {
    Love love = new You(); // 新建一个接口的属性，创建一个实现类的对象
    love.iLove(); // 通过实例来调用方法

    Love love1 = new Love() {
        @Override
        public void iLove() {
            System.out.println(&quot;i love you 1&quot;);
        }
    }; // 匿名内部类，不用实现类就可以直接通过接口进行方法的内部实现
    love1.iLove();

    Love love2 = () -&amp;gt; System.out.println(&quot;i love you 2&quot;);
    // lambda表达式对上面的简化，实质是一样的。不需要写new，也不需要写方法名（因为只有一个）;只有实现方法体
    love2.iLove();
}
// 如果有参数：Love love2 = (参数) -&amp;gt; System.out.println(&quot;i love you 2&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程的五大状态&lt;/h3&gt;
&lt;p&gt;含义：在Java程序中，一个线程对象只能调用一次&lt;code&gt;start()&lt;/code&gt;方法启动新线程，并在新线程中执行&lt;code&gt;run()&lt;/code&gt;方法。一旦&lt;code&gt;run()&lt;/code&gt;方法执行完毕，线程就结束了（死亡的线程无法再次&lt;code&gt;start&lt;/code&gt;）。因此，Java线程的状态有以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New：新创建的线程，尚未执行；&lt;/li&gt;
&lt;li&gt;Runnable：运行中的线程，正在执行&lt;code&gt;run()&lt;/code&gt;方法的Java代码；&lt;/li&gt;
&lt;li&gt;Blocked：运行中的线程，因为某些操作被阻塞而挂起；&lt;/li&gt;
&lt;li&gt;Waiting：运行中的线程，因为某些操作在等待中；&lt;/li&gt;
&lt;li&gt;Timed Waiting：运行中的线程，因为执行&lt;code&gt;sleep()&lt;/code&gt;方法正在计时等待；&lt;/li&gt;
&lt;li&gt;Terminated：线程已终止，因为&lt;code&gt;run()&lt;/code&gt;方法执行完毕。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;线程终止的原因有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程正常终止：&lt;code&gt;run()&lt;/code&gt;方法执行到&lt;code&gt;return&lt;/code&gt;语句返回；&lt;/li&gt;
&lt;li&gt;线程意外终止：&lt;code&gt;run()&lt;/code&gt;方法因为未捕获的异常导致线程终止；&lt;/li&gt;
&lt;li&gt;对某个线程的&lt;code&gt;Thread&lt;/code&gt;实例调用&lt;code&gt;stop()&lt;/code&gt;方法强制终止（强烈不推荐使用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个线程还可以等待另一个线程直到其运行结束。例如，&lt;code&gt;main&lt;/code&gt;线程在启动&lt;code&gt;t&lt;/code&gt;线程后，可以通过&lt;code&gt;t.join()&lt;/code&gt;等待&lt;code&gt;t&lt;/code&gt;线程结束后再继续运行。&lt;/p&gt;
&lt;h3&gt;线程方法&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;setPriority(int newPriority)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更改线程的优先级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;static void sleep(long millis)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在指定的毫秒数内让当前正在执行的线程休眠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;void join()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;等待该线程终止&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;static void yield()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;暂停当前正在执行的线程对象，并执行其他线程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;void interrupt()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;中断线程，&lt;strong&gt;别用这个方式&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;boolean isAlive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;测试线程是否处于活动状态&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;线程停止的方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;建议线程正常停止—&amp;gt;利用次数，不建议死循环。&lt;/li&gt;
&lt;li&gt;建议使用标志位—&amp;gt;设置一个标志位&lt;/li&gt;
&lt;li&gt;不要使用stop或者destroy等过时的方法&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;class ThreadStop implements Runnable { // 线程类
    private boolean flag = true; // 提供线程体中的标识
    public void run() {
        while (flag) { // 线程使用标识
            System.out.println(&quot;Thread is running&quot;);
        }
    }
    public void stop() { // 提供外部方法停止
        flag = false;
    }
    public static void main(String[] args) {
        ThreadStop threadStop = new ThreadStop();
        new Thread(threadStop).start();
        for (int i = 0; i &amp;lt; 999; i++) {
            if (i == 900)
                threadStop.stop(); // 调用线程类提供的公有方法
            System.out.println(&quot;main is running&quot;);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程休眠&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;作用：
&lt;ul&gt;
&lt;li&gt;模拟网络延时，放大问题的发生性-&amp;gt;（排查线程不安全）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;每个对象都有一个锁，&lt;code&gt;sleep&lt;/code&gt;不会释放锁&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;线程礼让&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;作用：
&lt;ul&gt;
&lt;li&gt;礼让线程，让当前正在执行的线程暂停，但不阻塞-&amp;gt;(礼让一下，再竞争一次)&lt;/li&gt;
&lt;li&gt;将线程从运行状态转为就绪状态&lt;/li&gt;
&lt;li&gt;让CPU重新调度，&lt;strong&gt;礼让不一定成功&lt;/strong&gt;！看CPU心情&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yield&lt;/code&gt;也不会释放锁&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;线程强制执行 join&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;可以将&lt;code&gt;join&lt;/code&gt;想象成插队，插主线程，很霸道，但是对于两个并行的线程无法直接插队&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;线程的优先级&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;如果有些比较重要的代码，需要先跑，可以设置优先级，虽然设置优先级并不一定会一定在前面先执行，但是至少他所占有的机会会变大一点&lt;/li&gt;
&lt;li&gt;默认为5,最高的优先级为10，最低为1，超范围报错&lt;/li&gt;
&lt;li&gt;线程优先级的两个方法&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;setPriority(级别); // 设置线程优先级
getPriority();     // 获取线程的优先级
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;守护线程&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;守护线程就像餐厅的服务员，而普通的用户线程就像是顾客，如果顾客都走光了，那么守护线程存在的意义也没有了，自然也会结束&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;常见的做法，就是将守护线程用于后台支持任务，比如垃圾回收、释放未使用对象的内存、从缓存中删除不需要的条目。&lt;/li&gt;
&lt;li&gt;咦，按照这个解释，那么大多数 &lt;code&gt;JVM&lt;/code&gt; 线程都是守护线程。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;守护线程的方法：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;setDaemon(true)  // 设置守护线程，注意，一定要在start方法之前设置守护线程；
isDaemon()       // 判断是否是守护线程
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程同步&lt;/h3&gt;
&lt;p&gt;形成条件：队列+锁&lt;/p&gt;
&lt;h4&gt;重点：synchronized到底锁的是谁&lt;/h4&gt;
&lt;p&gt;下面用一个实例来证明：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Date {
    public void func1() { // 普通方法
        try {
            Thread.sleep(3000); // 休眠3秒
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(&quot;1...&quot;);
    }

    public void func2() { // 普通方法
        System.out.println(&quot;2...&quot;);
    }
}

public static void main(String[] args) {
    Date date = new Date();
    new Thread(date::func1, &quot;A&quot;).start(); // lambda表达式启动线程
    try {
        Thread.sleep(1000); // 休眠1秒
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    new Thread(date::func2, &quot;B&quot;).start(); // lambda表达式启动线程
}
// 结果：1s后输出2...再过2秒后输出1...
// 原因：两个都是新起的线程，没有相关的同步性，按程序顺序执行
// 2...
// 1...
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;锁方法&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;普通方法：谁调用就锁谁&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public synchronized void func1() { // 把上面的修改为同步方法
public synchronized void func2() { // 把上面的修改为同步方法
// 结果：过了三秒同时输出,结果是先1...后2...
// 原因，锁了这个方法，谁来调用就锁哪个对象，这里只有一个对象date,所以先启动A线程，然后过了sleep3秒(不放锁)，主程序的sleep1秒对这里没有影响，直接就已经包含在sleep的3秒内了，因线程同步，三秒钟后，等A的锁释放，B立刻拿锁，输出
// 1...
// 2...
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public synchronized void func1() { // 把上面的修改为同步方法
public void func2() { // 普通方法
// 结果：1秒后输出2...再过2秒输出1...
// 原因：B线程不是同步的方法，直接就是两个线程在跑
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) { // 新建两个Date()对象
    Date date1 = new Date();
    Date date2 = new Date();
    new Thread(date1::func1, &quot;A&quot;).start();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    new Thread(date2::func2, &quot;B&quot;).start();
}

public synchronized void func1() { // 把上面的修改为同步方法
public synchronized void func2() { // 把上面的修改为同步方法
// 结果：1秒后输出2...再过2秒输出1...
// 原因：直接就是两个线程在跑，没有同步争夺资源
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;静态方法：锁定的是类&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) {
    Date date1 = new Date();
    Date date2 = new Date();
    new Thread(() -&amp;gt; {
        date1.func1();
    }, &quot;A&quot;).start();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    new Thread(() -&amp;gt; {
        date2.func2();
    }, &quot;B&quot;).start();
}

public static synchronized void func1() { // 变成了静态方法
public static synchronized void func2() { // 变成了静态方法
// 结果：过了三秒同时输出,结果是先1...后2...
// 原因：虽然date1与date2是两个不同的对象，但是因为静态同步方法锁的是这个类，两个对象都是来自同一个类，所以存在线程同步的关系。
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;修饰代码块&lt;/h5&gt;
&lt;p&gt;可以锁各种东西，放什么锁什么&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Date2 {
    public void func() {
        System.out.println(&quot;start...&quot;);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(&quot;end...&quot;);
    }
}

public static void main(String[] args) {
    Date2 date2 = new Date2();
    for (int i = 0; i &amp;lt; 5; i++) {
        new Thread(() -&amp;gt; {
            date2.func();
        }).start(); // 创建5个线程
    }
}
// 结果：直接是5个start，1秒后输出5end
// 原因：没有任何锁，直接是5个线程
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;// 只改变成同步代码块
public void func() {
    synchronized (this) { // 改成代码同步
        System.out.println(&quot;start...&quot;);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(&quot;end...&quot;);
    }
}
// 结果：在排队，交替输出start和end
// 原因：这里this是这个Date2的对象，只有一个date2对象，变成了线程同步
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) {
    for (int i = 0; i &amp;lt; 5; i++) {
        new Thread(() -&amp;gt; {
            Date2 date2 = new Date2(); // 只改变每次创建的对象
            date2.func();
        }).start();
    }
}
// 结果：在排队，交替输出start和end
// 原因：虽然同步代码块修饰了这个类创建的对象，但这时候对象创建放在了循环里，相当每次创建不同的对象，那么每次调用func方法就是直接开启新线程，没有线程同步
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;synchronized (Date2.class) { // 改成代码同步锁这个类
// 结果：在排队，交替输出start和end
// 原因：锁的是这个类，虽然创建的是5个不同的对象，但是都是同一个类，产生了线程同步
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;死锁&lt;/h4&gt;
&lt;p&gt;多个线程互相抱着对方需要的资源，然后形成僵持即一个线程可以获取一个锁后，再继续获取另一个锁。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void add(int m) {
    synchronized(lockA) { // 获得lockA的锁
        this.value += m;
        synchronized(lockB) { // 获得lockB的锁
            this.another += m;
        } // 释放lockB的锁
    } // 释放lockA的锁
}

public void dec(int m) {
    synchronized(lockB) { // 获得lockB的锁
        this.another -= m;
        synchronized(lockA) { // 获得lockA的锁
            this.value -= m;
        } // 释放lockA的锁
    } // 释放lockB的锁
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解决方案：一个线程可以获取一个锁后，再继续获取另一个锁。&lt;/p&gt;
&lt;p&gt;那么我们应该如何避免死锁呢？答案是：线程获取锁的顺序要一致，一次只获得一把锁，避免一个线程同时获得两把锁&lt;/p&gt;
&lt;h4&gt;lock锁&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;lock&lt;/code&gt;是显示锁，只能锁代码块&lt;/p&gt;
&lt;p&gt;好处：用&lt;code&gt;lock&lt;/code&gt;，&lt;code&gt;jvm&lt;/code&gt;将花费较少的时间调度线程，性能更好，可拓展性高&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class TestLock implements Runnable {
    private int ticket = 100;
    private final ReentrantLock lock = new ReentrantLock(); // 可重入的锁，一定要记住这个方法，通过他的lock和unlock方法实现同步
    @Override
    public void run() {
        while (true) {
            try {
                lock.lock(); // 在需要变化的地方设置锁
                if (ticket &amp;lt;= 0) {
                    return;
                } else {
                    System.out.println(ticket--);
                }
            } catch (RuntimeException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock(); // 一般放在finally块里释放锁
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程协作&lt;/h3&gt;
&lt;p&gt;生产者消费者模型具体来讲，就是在一个系统中，存在生产者和消费者两种角色，他们通过内存缓冲区进行通信，生产者生产消费者需要的资料，消费者把资料做成产品。（是一种问题，不是设计模式）&lt;/p&gt;
&lt;p&gt;再具体一点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生产者生产数据到缓冲区中，消费者从缓冲区中取数据。&lt;/li&gt;
&lt;li&gt;如果缓冲区已经满了，则生产者线程阻塞。&lt;/li&gt;
&lt;li&gt;如果缓冲区为空，那么消费者线程阻塞。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过wait()和notify()方法，采用 &lt;strong&gt;阻塞队列&lt;/strong&gt; 方式实现生产者消费者模式&lt;/p&gt;
&lt;h4&gt;管程法&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;class Producer extends Thread {
    // 生产者
    SynContainer Container;
    public Producer(SynContainer Container) {
        // 通过与消费者相同构造函数实现同一个线程
        this.Container = Container;
    }

    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 100; i++) {
            Container.push(new Chicken(i));
            System.out.println(&quot;生产力&quot; + i + &quot;鸡&quot;);
        }
    }
}

class Consumer extends Thread {
    // 消费者
    SynContainer Container;
    public Consumer(SynContainer Container) {
        // 通过与生产者相同构造函数实现同一个线程
        this.Container = Container;
    }

    @Override
    public void run() {
        for (int i = 0; i &amp;lt; 100; i++) {
            Chicken pop = Container.pop();
            System.out.println(&quot;消费类&quot; + pop.id + &quot;只鸡&quot;);
        }
    }
}

class Chicken { // 生产的对象
    int id; // 对象id
    public Chicken(int id) {
        this.id = id;
    }
}

class SynContainer {
    // 同步容器，锁就是锁他，通过他来实现中间的桥梁，使两个线程跑在这个上，变成并发
    Chicken[] chickens = new Chicken[10]; // 定义容器大小
    int count = 0; // 记录生成的数

    public synchronized void push(Chicken chicken) {
        if (count == chickens.length) {
            try {
                wait(); // 容器满了就会调用wait方法释放锁，让消费者先行
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        chickens[count++] = chicken;
        this.notifyAll(); // 释放锁
    }

    public synchronized Chicken pop() {
        if (count == 0) {
            try {
                wait(); // 没有消费对象的时候，就会wait释放锁，让生产者先行
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        count--;
        Chicken chicken = chickens[count];
        this.notifyAll(); // 释放锁
        return chicken;
    }
}

public static void main(String[] args) {
    SynContainer synContainer = new SynContainer();
    Producer producer = new Producer(synContainer);
    Consumer consumer = new Consumer(synContainer);
    producer.start();
    consumer.start();
}
// 结果：一个线程里，生产者与消费者正常是交错执行，如果满足了wait的条件，就释放了锁，给另外一方执行
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;线程池&lt;/h3&gt;
&lt;p&gt;思路：提前创建好多个线程，放入线程池中，使用时直接获取，使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。&lt;/p&gt;
&lt;p&gt;好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高响应速度（减少了创建新线程的时间）&lt;/li&gt;
&lt;li&gt;降低资源消耗（重复利用线程池中线程，不需要每次都创建）&lt;/li&gt;
&lt;li&gt;便于线程管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) {
    // 1.创建服务，创建线程池
    // newFixedThreadPool参数为：线程池大小
    ExecutorService service = Executors.newFixedThreadPool(10);
    // 执行
    service.execute(new 实现了Runnable接口的类);
    service.shutdown();
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>git 配置</title><link>https://210214.xyz/posts/git-config/</link><guid isPermaLink="true">https://210214.xyz/posts/git-config/</guid><description>Git常用配置和操作命令整理</description><pubDate>Mon, 20 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1.初始化配置&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git config --global user.name &quot;***&quot;
git config --global user.email &quot;***&quot;
git config --global http.sslVerift false
git config --list
git config --global core.autocrlf true
git config --global core.autocrlf input
git remote add origin
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.拉取代码&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git clone --recursive &apos;url&apos;
git pull
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3.分支操作&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# 也就是说当前的你的分支如果有代码的话你创建的新分支是不干净的
git checkout -b &apos;目录&apos;/&apos;分支名&apos;
git branch -a
git checkout &apos;需要切换的分支名称&apos;
git branch -d &apos;删除分支名称&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.代码提交&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git add .
git commit -m &apos;分支名称&apos;
git diff
git push
git push -f
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.配置代理&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[user]
    name = xxxx
    email = xxxxx@xxxx
[http &quot;https://github.com&quot;]
    proxy = http://127.0.0.1:7890
[http &quot;http://github.com&quot;]
    proxy = http://127.0.0.1:7890
[credential &quot;https://gitee.com&quot;]
    provider = generic
[http]
    sslverify = false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. gitignore规则&lt;/h2&gt;
&lt;h3&gt;语法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#&lt;/code&gt;作为注释&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt;开头表示目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt;通配符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt;匹配单个字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[]&lt;/code&gt;包含单个字符的匹配规则&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!&lt;/code&gt;忽略目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;用法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;*.txt ，*.xls 表示过滤某种类型的文件
target/ ：表示过滤这个文件夹下的所有文件
/test/a.txt ，/test/b.xls 表示指定过滤某个文件下具体文件
!*.java , !/dir/test/ !开头表示不过滤
*.[ab] 支持通配符：过滤所有以.a或者.b为扩展名的文件
/test 仅仅忽略项目根目录下的 test 文件，不包括 child/test等非根目录的 test 目录
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;.gitignore&lt;/h3&gt;
&lt;p&gt;有些时候我们不想把某些文件纳入版本控制中，比如数据库文件，临时文件等&lt;/p&gt;
&lt;p&gt;在主目录下建立&quot;.gitignore&quot;文件，此文件有如下规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;忽略文件中的空行或以井号（#）开始的行将会被忽略。&lt;/li&gt;
&lt;li&gt;可以使用Linux通配符。例如：星号（*）代表任意多个字符，问号（？）代表一个字符，方括号 （[abc]）代表可选字符范围，大括号（{string1,string2,…}）代表可选的字符串等。&lt;/li&gt;
&lt;li&gt;如果名称的最前面有一个感叹号（!），表示例外规则，将不被忽略。&lt;/li&gt;
&lt;li&gt;如果名称的最前面是一个路径分隔符（/），表示要忽略的文件在此目录下，而子目录中的文件不 忽略。&lt;/li&gt;
&lt;li&gt;如果名称的最后面是一个路径分隔符（/），表示要忽略的是此目录下该名称的子目录，而非文件 （默认文件或目录都忽略）。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;*.txt
!lib.txt
/temp
build/
doc/*.txt
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item></channel></rss>