<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on YUKIPEDIA</title><link>https://yukipedia.cn/posts/</link><description>Recent content in Posts on YUKIPEDIA</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sat, 13 Sep 2025 00:00:00 +0800</lastBuildDate><atom:link href="https://yukipedia.cn/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>浅谈 JVM 垃圾回收机制</title><link>https://yukipedia.cn/posts/2025/09/13/jvm-recycle/</link><pubDate>Sat, 13 Sep 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/09/13/jvm-recycle/</guid><description>&lt;h2 id="垃圾回收的概念从何而来"&gt;垃圾回收的概念从何而来&lt;/h2&gt;&#10;&lt;p&gt;垃圾回收（Garbage Collection, GC），顾名思义就是释放垃圾占用的空间，避免爆内存。具体来说，垃圾回收需要对 &lt;strong&gt;堆内存&lt;/strong&gt; 中已经死亡或者长时间未使用的对象进行清除回收。&lt;/p&gt;</description></item><item><title>记：沙箱环境变量不生效 Bug 排查</title><link>https://yukipedia.cn/posts/2025/08/30/env-vars-of-sandbox/</link><pubDate>Sat, 30 Aug 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/08/30/env-vars-of-sandbox/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;&#10;&lt;p&gt;接到 &lt;a href="https://github.com/TencentBlueKing/blueking-paas"&gt;blueking-paas&lt;/a&gt; 沙箱自定义环境变量的需求后，照常先进行需求分析、产品设计，然后编写代码 + 本地 API 测试 + 提 PR，接下来就是愉快的和前端联调了。&lt;/p&gt;&#10;&lt;p&gt;之后流水线发布到联调环境，前端通知自测，自己在界面上到处点点点也没发现什么问题（现在看确实缺少一些测试经验 orz）。于是写了份体验文档扔到群里，让其他同事也测试看看，没问题的话就可以发布到预发布环境 &amp;amp; 正式环境，上线这个功能了。&lt;/p&gt;</description></item><item><title>不负责任の音游简史 &amp; 音游种类简单科普</title><link>https://yukipedia.cn/posts/2025/06/29/brief-history-of-rhythm-games/</link><pubDate>Sun, 29 Jun 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/06/29/brief-history-of-rhythm-games/</guid><description>&lt;p&gt;说起音乐游戏，可能很多人印象比较深刻的是由我们事业群下光子工作室发行的《节奏大师》。对于我来说，从小到大接触的第一款音乐游戏也是它。让我们从《节奏大师》这种下落式的游戏模式出发，去了解音乐游戏的起源和发展吧 ~&lt;/p&gt;</description></item><item><title>常用设计模式&amp;面向对象设计法则</title><link>https://yukipedia.cn/posts/2025/06/18/design-pattern/</link><pubDate>Wed, 18 Jun 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/06/18/design-pattern/</guid><description>&lt;h2 id="常用的设计模式"&gt;常用的设计模式&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;创建型&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Factory Method (工厂方法)&lt;/strong&gt;：“ &lt;strong&gt;让子类决定生产什么对象&lt;/strong&gt; ”，父类定规则，子类做决定，把对象的创建延迟到子类，避免硬编码 new&#10;&lt;ul&gt;&#10;&lt;li&gt;解决了什么问题？&#10;&lt;ul&gt;&#10;&lt;li&gt;解耦，客户端（&lt;code&gt;Main&lt;/code&gt; 类）不需要知道具体实现，只依赖抽象&lt;/li&gt;&#10;&lt;li&gt;扩展性，新增种类时只需要增加新的实现类&lt;/li&gt;&#10;&lt;li&gt;符合开闭原则&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Abstract Factory (抽象工厂方法)&lt;/strong&gt;：“ &lt;strong&gt;一站式生产整套产品&lt;/strong&gt; ”，定义一个超级工厂接口，让具体工厂生产同一品牌的全套产品&#10;&lt;ul&gt;&#10;&lt;li&gt;解决了什么问题？&#10;&lt;ul&gt;&#10;&lt;li&gt;保证产品兼容性&lt;/li&gt;&#10;&lt;li&gt;切换产品族方便&lt;/li&gt;&#10;&lt;li&gt;符合开闭原则&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Builder(建造者模式)&lt;/strong&gt;：“ &lt;strong&gt;分步骤组装复杂对象&lt;/strong&gt; ”，当一个对象参数很多，用构造函数传参会很臃肿，并且难以扩展。可以采用 Builder 模式，&lt;strong&gt;分步骤设置参数&lt;/strong&gt;，最后统一组装对象&#10;&lt;ul&gt;&#10;&lt;li&gt;解决了什么问题？&#10;&lt;ul&gt;&#10;&lt;li&gt;参数灵活，可以只设置需要的参数&lt;/li&gt;&#10;&lt;li&gt;代码可读，链式调用清晰表达组装逻辑&lt;/li&gt;&#10;&lt;li&gt;避免无效状态，通过 &lt;code&gt;build()&lt;/code&gt; 方法统一校验参数&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Singleton(单例模式)&lt;/strong&gt;：“ &lt;strong&gt;一个类只能有一个实例&lt;/strong&gt; ”，某些对象（如配置管理器、数据库连接池）必须&lt;strong&gt;全局唯一&lt;/strong&gt;，重复创建会浪费资源或导致数据不一致&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;结构型&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Adapter(适配器模式)&lt;/strong&gt;：“ &lt;strong&gt;转换接口，兼容新旧&lt;/strong&gt; ”，两个系统或类因为&lt;strong&gt;接口不兼容&lt;/strong&gt;无法直接合作（比如老代码调用新库，或第三方接口不匹配）。适配器模式加一个 &lt;strong&gt;中间层（适配器）&lt;/strong&gt;，把 “旧接口” 转换成 “新接口”&#10;&lt;ul&gt;&#10;&lt;li&gt;举个例子，假设你的电商系统需要同时支持 &lt;strong&gt;微信支付&lt;/strong&gt; 和 &lt;strong&gt;支付宝&lt;/strong&gt;，但它们的接口完全不同：微信的接口返回 boolean 表示成功与否，支付宝返回 PayResult 对象。但你希望对外提供统一的支付接口，屏蔽底层差异，这里就可以使用 adaptor&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Bridge(桥接模式)&lt;/strong&gt;：“ &lt;strong&gt;把抽象和实现分开，让它们自由组合&lt;/strong&gt; ”，当一个类有多个变化维度（比如“形状”和“颜色”），用继承会导致类爆炸（不用为每种组合创建子类）&#10;&lt;ul&gt;&#10;&lt;li&gt;类比一下，&lt;strong&gt;抽象&lt;/strong&gt; 相当于遥控器的按钮（开/关、调音量），&lt;strong&gt;实现&lt;/strong&gt; 相当于不同品牌的电视（索尼、小米），&lt;strong&gt;桥接&lt;/strong&gt; 相当于遥控器持有电视的引用，但不知道具体品牌&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Decorator(装饰器模式)&lt;/strong&gt;：“ &lt;strong&gt;给对象动态加功能，像套娃一样层层包装&lt;/strong&gt; ”，当我们想给一个对象添加新功能，但不想修改它的源代码（避免破坏原有逻辑），就可以用 &lt;strong&gt;装饰器类&lt;/strong&gt; 包裹原始对象，在 &lt;strong&gt;不改变原对象&lt;/strong&gt; 的基础上，动态添加功能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Flyweight(享元模式)&lt;/strong&gt;：“ &lt;strong&gt;共享相同部分，节省内存&lt;/strong&gt; ”，当程序需要创建&lt;strong&gt;大量相似对象&lt;/strong&gt;时（比如游戏中的子弹、棋子、文字），每个对象都独立存储数据会浪费内存，我们就可以采用 &lt;strong&gt;享元模式&lt;/strong&gt;，拆分对象的属性为内部状态（不变的、可共享的数据）和外部状态（变化的，不可共享的数据）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Proxy(代理模式)&lt;/strong&gt;：“ &lt;strong&gt;找个替身帮你干活&lt;/strong&gt; ”，直接访问某个对象可能会带来问题（比如性能开销、权限控制、远程调用等），于是我们引入一个代理对象，在客户端和目标对象之间加一层控制，由代理决定如何处理请求&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;行为型&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Template(模板方法模式)&lt;/strong&gt;：“ &lt;strong&gt;定好流程大纲，具体步骤自己填&lt;/strong&gt; ” ，多个任务有 &lt;strong&gt;相同的流程&lt;/strong&gt;，但某些步骤的具体实现不同（比如做咖啡和泡茶，步骤类似，但细节不同），于是我们可以抽象父类的整体流程（模板方法），子类只需要实现自己需要定制的步骤&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Method(方法模式)&lt;/strong&gt;：“ &lt;strong&gt;把复杂操作拆成小步骤，让代码更清晰&lt;/strong&gt; ”，当一个方法过于复杂（比如几十行代码，混合了多种逻辑），会导致难以阅读和维护，并且无法复用部分代码，于是我们 &lt;strong&gt;把大方法拆分成多个小方法&lt;/strong&gt;，每个小方法只做一件事，再组合起来完成大功能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Chain Of Responsibility(责任链模式)&lt;/strong&gt;：&amp;quot; &lt;strong&gt;踢皮球，一个请求在多个对象之间传递&lt;/strong&gt; &amp;ldquo;，一个请求需要经过多个处理者，但不确定具体由谁处理（比如不同金额的报销需要不同级别审批），于是我们把多个处理者串成一条链，请求沿着链传递，直到被处理或链结束&#10;&lt;ul&gt;&#10;&lt;li&gt;解决了什么问题？&#10;&lt;ul&gt;&#10;&lt;li&gt;解耦，请求发送者不需要知道具体谁处理&lt;/li&gt;&#10;&lt;li&gt;动态调整，可以随时增减或调整处理者顺序&lt;/li&gt;&#10;&lt;li&gt;灵活性，每个处理者只需关注自己的责任范围&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Iterator(迭代器模式)&lt;/strong&gt;：“ &lt;strong&gt;统一遍历所有对象，不关心底层结构&lt;/strong&gt; ”，不同的集合（如数组、链表、树）遍历方式不同，直接暴露内部结构会让代码混乱，于是提供统一的遍历接口，隐藏集合的内部实现&#10;&lt;ul&gt;&#10;&lt;li&gt;解决了什么问题？&#10;&lt;ul&gt;&#10;&lt;li&gt;解耦，遍历代码不依赖具体集合实现（数组、链表、树都能用同一套遍历逻辑）&lt;/li&gt;&#10;&lt;li&gt;简化调用，用户只需调 &lt;code&gt;hasNext()&lt;/code&gt; 和 &lt;code&gt;next()&lt;/code&gt;，不用关心底层是 &lt;code&gt;for&lt;/code&gt; 循环还是 &lt;code&gt;while&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Observer(观察者模式)&lt;/strong&gt;：“ &lt;strong&gt;微信订阅号，作者发布，粉丝自动收到推送&lt;/strong&gt; ”，当一个对象（如天气数据）变化时，需要自动通知多个依赖对象（如手机App、广告牌），但 &lt;strong&gt;不想让它们紧密耦合&lt;/strong&gt;，我们可以这样解决：&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;被观察者（Subject）&lt;/strong&gt;：维护一个订阅者列表，提供 &lt;code&gt;添加/删除&lt;/code&gt; 订阅的方法&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;观察者（Observer）&lt;/strong&gt;：定义统一的更新接口（如 &lt;code&gt;update()&lt;/code&gt;）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;流程&lt;/strong&gt;：被观察者状态变化 → 遍历订阅者列表 → 调用每个观察者的 &lt;code&gt;update()&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;State(状态模式)&lt;/strong&gt;：“ &lt;strong&gt;对象变，行为跟着变&lt;/strong&gt; ”，当一个对象的行为 &lt;strong&gt;取决于它的状态&lt;/strong&gt;（比如订单的 “待支付”、“已发货”），如果用一堆 &lt;code&gt;if-else&lt;/code&gt; 判断状态，代码会臃肿且难维护，于是我们可以 &lt;strong&gt;把状态抽成独立的类&lt;/strong&gt;，对象内部切换状态，行为自动变化&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Strategy(策略模式)&lt;/strong&gt;：“ &lt;strong&gt;算法随便换，调用不改变&lt;/strong&gt; ”，当一个任务有 &lt;strong&gt;多种算法&lt;/strong&gt;（如排序、支付、导航），用 &lt;code&gt;if-else&lt;/code&gt; 硬编码会导致代码臃肿且难扩展，于是我们可以定义算法接口，将每种算法封装成独立类，运行时动态的切换算法，调用方无需关心细节&#10;&lt;ul&gt;&#10;&lt;li&gt;比如导航 App，选 “最快路线” 或 “最省钱路线”，App 自动计算，但导航按钮始终是同一个；支付系统，用户选微信支付或支付宝，支付流程不变，只是底层实现不同&lt;/li&gt;&#10;&lt;li&gt;解决了什么问题？&#10;&lt;ul&gt;&#10;&lt;li&gt;开闭原则，新增算法只需要加新类，不需要改旧代码&lt;/li&gt;&#10;&lt;li&gt;复用性，同一套算法可被多个场景共享&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="面向对象oo的设计法则"&gt;面向对象（OO）的设计法则&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;单一职责原则：一个类只干一件事&lt;/li&gt;&#10;&lt;li&gt;开闭原则：对扩展开放，对修改关闭&lt;/li&gt;&#10;&lt;li&gt;里氏替换原则：子类必须能替换父类，且行为一致（防止调用父类方法时，子类抛出 &lt;strong&gt;不支持的操作&lt;/strong&gt; 异常）&lt;/li&gt;&#10;&lt;li&gt;接口隔离原则：接口要小而专，不能让用户实现用不到的方法&#10;&lt;ul&gt;&#10;&lt;li&gt;比如：Animal 接口有 fly()、swim()、run()，但 Dog 类被迫实现无用的 fly()&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;依赖倒置原则：依赖抽象，不依赖具体&#10;&lt;ul&gt;&#10;&lt;li&gt;比如：&#10;&lt;ul&gt;&#10;&lt;li&gt;错误设计：OrderService 直接调用 MySQLDatabase&lt;/li&gt;&#10;&lt;li&gt;正确设计：OrderService 依赖 Database 接口，具体用 MySQL 还是 Mongo 由配置决定&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;迪米特法则：少管闲事，只和朋友通信（减少类之间的耦合）&lt;/li&gt;&#10;&lt;li&gt;组合由于继承原则：多用组合，少用继承&lt;/li&gt;&#10;&lt;/ol&gt;</description></item><item><title>kaniko 与 buildpacks, slugbuilder, slugrunner</title><link>https://yukipedia.cn/posts/2025/05/30/kaniko-buildpacks-slugbuilder-slugrunner/</link><pubDate>Fri, 30 May 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/05/30/kaniko-buildpacks-slugbuilder-slugrunner/</guid><description>&lt;h1 id="kaniko"&gt;kaniko&lt;/h1&gt;&#10;&lt;h2 id="什么是-kaniko"&gt;什么是 kaniko？&lt;/h2&gt;&#10;&lt;p&gt;学习 kaniko 之前，先要了解什么是 docker daemon&#10;docker daemon（docker 守护进程） 是 docker 的核心后台服务，在后台管理所有与容器相关的事情&#10;比如：&lt;/p&gt;</description></item><item><title>前后端跨域</title><link>https://yukipedia.cn/posts/2025/05/27/cookie/</link><pubDate>Tue, 27 May 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/05/27/cookie/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;&#10;&lt;p&gt;在某个晚上搭建 apiserver 和 webfe 环境，启动前后端项目后在浏览器访问服务器的域名，出现了返回的状态码为 200，但是前端却拿不到后端数据，即跨域问题。寻求 mt 的帮助后解决了这个问题，收获不小，记录一下&lt;/p&gt;</description></item><item><title>微服务体系结构、Nacos 和熔断器</title><link>https://yukipedia.cn/posts/2025/02/11/nacos-and-fuses/</link><pubDate>Tue, 11 Feb 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/02/11/nacos-and-fuses/</guid><description>&lt;h2 id="微服务四大设计原则"&gt;微服务四大设计原则&lt;/h2&gt;&#10;&lt;h3 id="独立部署"&gt;独立部署&lt;/h3&gt;&#10;&lt;p&gt;每个微服务都应该能够独立部署、升级和扩展，而不影响其他微服务的正常运行。独立部署使得微服务架构能够灵活应对变化，无论是业务需求变化、性能优化，还是技术更新，都能以最小的代价进行。&lt;/p&gt;</description></item><item><title>在 MySQL 集群中，在从库已经读到了最新值的情况下，主库还有可能读到旧值吗？</title><link>https://yukipedia.cn/posts/2025/01/18/mysql-cluster/</link><pubDate>Sat, 18 Jan 2025 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2025/01/18/mysql-cluster/</guid><description>&lt;p&gt;参考：https://golangguide.top/&lt;/p&gt;&#10;&lt;p&gt;对于 MySQL 数据库，为了得到更高的性能，一般会搭建 MySQL 集群实现&lt;strong&gt;读写分离&lt;/strong&gt;，主库用于写操作，从库用于读操作。虽然主库一般用于写，但也是能读的。那么就有这样一个问题：&lt;strong&gt;在 MySQL 集群中，在从库已经读到了最新值的情况下，主库还有可能读到旧值吗？&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>IntelliJ IDEA 中 Lombok 注解失效问题</title><link>https://yukipedia.cn/posts/2024/12/11/lombok-annotation-failure-issue/</link><pubDate>Wed, 11 Dec 2024 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2024/12/11/lombok-annotation-failure-issue/</guid><description>&lt;h2 id="问题"&gt;问题&lt;/h2&gt;&#10;&lt;p&gt;尝试在 IDEA 中使用 Lombok 注解，但是在程序编译时出现找不到 &lt;code&gt;get&amp;amp;set&lt;/code&gt; 方法、找不到 &lt;code&gt;builder&lt;/code&gt; 方法等报错，但在对应的类中都已经加上了 &lt;code&gt;@Data&lt;/code&gt; 和 &lt;code&gt;@Builder&lt;/code&gt; 注解，但是编译器找不到注解。&lt;/p&gt;&#10;&lt;h2 id="解决方法"&gt;解决方法&lt;/h2&gt;&#10;&lt;p&gt;确保安装了 Lombok 插件，（&lt;code&gt;Settings&lt;/code&gt; → &lt;code&gt;Plugins&lt;/code&gt; 安装 &lt;code&gt;lombok&lt;/code&gt;）&lt;/p&gt;</description></item><item><title>泛型与函数式编程</title><link>https://yukipedia.cn/posts/2024/11/07/generics-and-functional-programming/</link><pubDate>Thu, 07 Nov 2024 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2024/11/07/generics-and-functional-programming/</guid><description>&lt;h2 id="泛型与函数式编程"&gt;泛型与函数式编程&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;函数式编程：在Java中，函数式编程是一种编程范式，它把计算视为数学上的函数求值，并且避免了状态和可变数据。这意味着在函数式编程中，函数是“一等公民”，&lt;strong&gt;它们可以作为参数传递给其他函数，也可以作为结果从函数中返回&lt;/strong&gt;。此外，函数式编程鼓励使用不可变对象来减少副作用，从而提高代码的可读性和可维护性。&lt;/li&gt;&#10;&lt;li&gt;泛型：泛型是Java语言的一个重要特性，它允许你在定义类、接口和方法时使用&lt;strong&gt;类型参数&lt;/strong&gt;。这样做的好处是&lt;strong&gt;可以重用相同的代码来处理不同的数据类型&lt;/strong&gt;，同时还能获得编译时的类型安全检查，避免运行时出现类型错误。简单来说，泛型就是一种参数化类型的机制，即所操作的数据类型可以被指定为一个参数，这种参数类型可以在使用时确定。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="应用"&gt;应用&lt;/h2&gt;&#10;&lt;p&gt;我们以下面的需求为例子：&lt;/p&gt;</description></item><item><title>基于 Redis 的用户短信登陆功能</title><link>https://yukipedia.cn/posts/2024/11/06/redis-login/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2024/11/06/redis-login/</guid><description>&lt;h2 id="1发送验证码功能实现"&gt;1.发送验证码功能实现&lt;/h2&gt;&#10;&lt;p&gt;前端会给后端传入 String 和一个 HttpSession ，然后对应的 controller 调用 service 层的 &lt;code&gt;sendCode&lt;/code&gt; 方法：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 发送手机验证码&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@PostMapping&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Result &lt;span style="color:#a6e22e"&gt;sendCode&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;@RequestParam&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;phone&amp;#34;&lt;/span&gt;) String phone, HttpSession session) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; userService.&lt;span style="color:#a6e22e"&gt;sendCode&lt;/span&gt;(phone, session);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 &lt;code&gt;RandomUtil&lt;/code&gt; 实现随机生成验证码并保存到 redis 中。&lt;strong&gt;此处的返回验证码仅仅是模拟返回过程&lt;/strong&gt;，并不是真实返回。&lt;/p&gt;</description></item><item><title>通过 AOP 和反射实现不同表的公共字段自动填充</title><link>https://yukipedia.cn/posts/2024/09/04/aop/</link><pubDate>Wed, 04 Sep 2024 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2024/09/04/aop/</guid><description>&lt;h2 id="项目问题场景"&gt;项目问题场景&lt;/h2&gt;&#10;&lt;p&gt;当前端页面涉及到&lt;strong&gt;新增或更新&lt;/strong&gt;数据操作时，在后端数据库中会有更新某些公共字段的需求，比如创建时间、更新时间、创建人等等。&lt;/p&gt;&#10;&lt;p&gt;比如下面的 &lt;code&gt;service&lt;/code&gt; 层代码：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 新增员工&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param employeeDTO&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;save&lt;/span&gt;(EmployeeDTO employeeDTO) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.&lt;span style="color:#a6e22e"&gt;out&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;println&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;当前线程的 id：&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; Thread.&lt;span style="color:#a6e22e"&gt;currentThread&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;getId&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Employee employee &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Employee();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 对象属性拷贝，将前者的属性拷贝到后者的属性上，前提是两者的属性名一致&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; BeanUtils.&lt;span style="color:#a6e22e"&gt;copyProperties&lt;/span&gt;(employeeDTO, employee);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置账号状态，默认正常状态 1表示正常，0表示锁定&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setStatus&lt;/span&gt;(StatusConstant.&lt;span style="color:#a6e22e"&gt;ENABLE&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 用常量类来设置，不用具体的数字（硬编码）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置密码，默认为 123456，同样使用常量类来设置&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setPassword&lt;/span&gt;(DigestUtils.&lt;span style="color:#a6e22e"&gt;md5DigestAsHex&lt;/span&gt;(PasswordConstant.&lt;span style="color:#a6e22e"&gt;DEFAULT_PASSWORD&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getBytes&lt;/span&gt;()));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置当前记录的创建时间和修改时间&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setCreateTime&lt;/span&gt;(LocalDateTime.&lt;span style="color:#a6e22e"&gt;now&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setUpdateTime&lt;/span&gt;(LocalDateTime.&lt;span style="color:#a6e22e"&gt;now&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置当前记录创建人 id 和修改人 id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setCreateUser&lt;/span&gt;(BaseContext.&lt;span style="color:#a6e22e"&gt;getCurrentId&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setUpdateUser&lt;/span&gt;(BaseContext.&lt;span style="color:#a6e22e"&gt;getCurrentId&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employeeMapper.&lt;span style="color:#a6e22e"&gt;insert&lt;/span&gt;(employee);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/**&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * 编辑员工信息&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; * @param employeeDTO&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt; */&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;update&lt;/span&gt;(EmployeeDTO employeeDTO) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Employee employee &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Employee();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; BeanUtils.&lt;span style="color:#a6e22e"&gt;copyProperties&lt;/span&gt;(employeeDTO, employee);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setUpdateTime&lt;/span&gt;(LocalDateTime.&lt;span style="color:#a6e22e"&gt;now&lt;/span&gt;());&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employee.&lt;span style="color:#a6e22e"&gt;setUpdateUser&lt;/span&gt;(BaseContext.&lt;span style="color:#a6e22e"&gt;getCurrentId&lt;/span&gt;()); &lt;span style="color:#75715e"&gt;// 获取操作人 id，此处是通过拦截器的 thread 获取对应信息&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; employeeMapper.&lt;span style="color:#a6e22e"&gt;update&lt;/span&gt;(employee);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;其中更新 &lt;code&gt;updateTime&lt;/code&gt; 、&lt;code&gt;setUpdateUser&lt;/code&gt; 等操作在重复的调用相同的 &lt;code&gt;set&lt;/code&gt; 方法&lt;/strong&gt;，会增加代码的冗余且不便于后期维护。&lt;/p&gt;</description></item><item><title>如何爬取厦大智慧教务签到码</title><link>https://yukipedia.cn/posts/2024/07/30/xmu-checkin/</link><pubDate>Tue, 30 Jul 2024 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2024/07/30/xmu-checkin/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;&#10;&lt;p&gt;本文是作者在学习计算机网络八股文的过程中做的小实践，&lt;strong&gt;仅供学习使用&lt;/strong&gt;，请勿使用此方法逃避考勤。&lt;/p&gt;&#10;&lt;h2 id="操作过程"&gt;操作过程&lt;/h2&gt;&#10;&lt;h3 id="爬取签到码前需要准备什么"&gt;爬取签到码前需要准备什么？&lt;/h3&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;一台可以联网并且安装有微信的电脑&lt;/li&gt;&#10;&lt;li&gt;一个可以抓取网络流量包的软件（我使用的是Proxyman）&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="抓包过程"&gt;抓包过程&lt;/h3&gt;&#10;&lt;p&gt;使用电脑登陆微信，搜索厦大智慧教务小程序并打开&lt;/p&gt;</description></item><item><title>大一随笔</title><link>https://yukipedia.cn/posts/2024/07/29/first-year-record/</link><pubDate>Mon, 29 Jul 2024 00:00:00 +0800</pubDate><guid>https://yukipedia.cn/posts/2024/07/29/first-year-record/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;&#10;&lt;p&gt;我高考录取到的专业并不是计算机而是建筑，因此我的整个大一是在思明校区度过的。可能是从小和电脑打交道比较早（？），也可能是看到将来的就业前（钱）景，进入厦大后萌生出转专业到计算机的想法。我开始写这篇博客的时间是 2024年 7 月 25 日的 23:08，因此本篇记录的快乐大一时光大多基于我对手机上万张照片的回忆~~~&lt;/p&gt;</description></item></channel></rss>