private plot

应无所住 | 而生其心

在项目中,我们常常会遇到 Entity → VO 转换 的场景。除了 VO 和 Assembler 的取舍,另一个经常讨论的问题是:查询逻辑应该放在哪里?
这篇文章记录了完整的思考过程。

阅读全文 »

目标:用 抽象语法树(AST) 的方式剖析英语句子,训练 结构化理解可复用模板化 能力。

阅读全文 »

快速、可复用的 SQL 与 Excel 批量处理技巧集合,覆盖:关联更新、拼接更新、替换更新、拼接查询以生成初始化 SQL、Excel 自动生成建表语句与 IN 列表。

阅读全文 »

摘要
在多业务统一入口的场景中,业务类型动态分发与公共逻辑复用是核心挑战。本文总结一种优雅且高扩展的解决方案,涵盖两个重点:

  1. 基于自定义注解 + Spring容器 Bean 管理 + 代理兼容实现的策略模式
  2. 接口与抽象类配合,定义契约并复用公共实现,实现解耦和结构清晰

1. 注解驱动的策略注册机制(伪代码)

自定义注解

1
2
3
4
5
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BizModel {
String value();
}

策略工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class StrategyFactory {

private Map<String, StrategyInterface> strategyMap = new HashMap<>();

public StrategyFactory(Map<String, StrategyInterface> strategies) {
for (StrategyInterface strategy : strategies.values()) {
Class<?> realClass = SpringAopUtils.getTargetClass(strategy);
BizModel annotation = realClass.getAnnotation(BizModel.class);
if (annotation != null) {
strategyMap.put(annotation.value(), strategy);
}
}
}

public StrategyInterface getStrategy(String key) {
StrategyInterface strategy = strategyMap.get(key);
if (strategy == null) throw new RuntimeException("未找到策略:" + key);
return strategy;
}
}

策略实现示例

1
2
3
4
5
6
7
8
9
@Service
@BizModel("业务标识1")
public class ConcreteStrategyA extends AbstractStrategyBase {

@Override
protected void doBusinessLogic(DTO dto) {
// 业务特有逻辑实现
}
}

2. 接口 + 抽象类的协同设计(伪代码)

定义接口(契约)

1
2
3
public interface StrategyInterface {
void execute(DTO dto);
}

抽象类(公共流程模板)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class AbstractStrategyBase implements StrategyInterface {

@Override
public void execute(DTO dto) {
validate(dto);
preProcess(dto);

doBusinessLogic(dto); // 子类实现差异化

postProcess(dto);
}

protected abstract void doBusinessLogic(DTO dto);

private void validate(DTO dto) {
// 公共校验逻辑
}

private void preProcess(DTO dto) {
// 公共预处理
}

private void postProcess(DTO dto) {
// 公共后处理
}
}

3. 运行时调用示意(伪代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
public class Controller {

private final StrategyFactory factory;

public Controller(StrategyFactory factory) {
this.factory = factory;
}

public Response handleRequest(RequestDTO dto) {
StrategyInterface strategy = factory.getStrategy(dto.getBizModel());
strategy.execute(dto);
return Response.success();
}
}

总结

利用注解驱动 + Spring自动装配实现业务类型到策略实现的动态路由,方便扩展。
通过接口定义契约,抽象类封装公共流程,实现代码复用与解耦。
设计既减少重复代码,又保证系统灵活性和维护便利。

摘要
这是一篇对自己的复盘文章,从职业习惯、思维模式和生活方式三个角度,总结了我的优势与不足,并提出了具体的改进方法。核心关注点是如何在保持专业与细节追求的同时,降低完美主义带来的成本、提高沟通效率、减少任务切换的损耗。

前言

这篇文章是一次对自己的回顾与整理,结合近期的工作习惯、技术思路以及生活节奏,总结我是什么样的人、有哪些不足,以及针对不足的改进方向。


我的特点

  1. 专业能力强
    作为一名 Java 后端开发者,我在业务实现中注重代码质量,熟悉 Clean Code 原则,能写出简洁、易测、结构清晰的代码。对 SICP 这类计算机科学经典思想也有一定的理解,并在实践中贯彻。

  2. 逻辑严谨
    处理问题时习惯从原理层面切入,比较不同方案的优劣,而不是仅停留在能用的层面。

  3. 学习驱动
    主动钻研 SQL、网络、编译原理等底层知识,保持对技术细节的敏感。

  4. 生活有节奏
    饮食、作息相对稳定,有长期健康意识。

  5. 审美有取向
    偏好含蓄的东方美学,这种审美观也影响了我对代码和设计风格的追求——克制、简洁、有韵味。


我的不足

  1. 完美主义倾向
    常常在功能已可用的情况下,花额外精力去打磨细节。例如,在简单的字符串拼接中犹豫要不要用 String.format,或者在 Maven 打包已正常完成的情况下,仍想验证编译警告是否影响速度。这种追求虽然保证了质量,但容易在非关键环节投入过多时间。

  2. 信息密度过高
    在沟通时倾向一次性提供大量上下文与技术细节。虽然信息完整,但接收方需要先拆解再理解,降低了沟通效率。

  3. 任务切换成本高
    在深入一个任务后切换到另一任务时,需要花时间恢复思路。这与记忆力关系不大,更多是处理问题方式造成的:我倾向长时间深度专注,但缺少任务切换前的“外部缓存”动作。


改进方向

1. 优先级分层

  • 方法:使用“30 秒优先级评估法”快速判断当前优化是否影响核心功能或交付时间。
  • 目标:每天至少推迟 1 个非关键优化任务,观察是否对结果造成实际影响。

2. 降低信息密度

  • 方法:采用“3 段式提问法”——背景一句话、问题一句话、补充信息按需提供。
  • 目标:每天至少用一次 3 段式提问,评估反馈速度。

3. 减少切换损耗

  • 方法:切任务前,用 1-2 句话记录当前进度与下一步动作,作为外部缓存。
  • 目标:每天记录 3 次切换笔记,确保切回任务时能在 2 分钟内进入状态。

结语

这不是一次对自己的苛责,而是一次客观的整理与优化。
优势要保持,不足要改进,习惯要固化。
持续的小改进,会带来长期的大变化

在函数设计中,我们常常会遇到一个令人纠结的问题:参数的合法性由谁负责校验?

我们以如下函数为例:

1
2
3
4
5
6
7
8
9
10
public OmsMockResponse<String> pushBySynRecord(SynRecord synRecord) {
...
OmsInboundOrderResponse inbound = getOmsInboundOrder(order.getContainerNo());
if (inbound == null) {
return new OmsMockResponse<>(400, "未找到入库单", null);
}

OmsInboundExpectedDatePushRequest request = buildRequest(order, inbound);
...
}

🧩 1. 谁使用,谁负责
这是最基础的原则:

如果你要用某个值,比如调用 inbound.getInboundOrderNo(),你就要保证这个值有效。

因此,buildRequest 要负责检查 inboundOrderNo 是否为空,而不是调用者 pushBySynRecord。

✅ 谁使用字段,谁就对它的存在性和合法性负责。

🧩 2. 谁输出,谁负责
buildRequest 要负责返回一个结构完整、语义清晰的 Request 实例,它就要确保 expectedDate、inboundOrderNo 都不为空,哪怕调用者传了问题数据,也应该 fail fast。

✅ 被调用方有责任保证其输出对象的完整性。

🧩 3. 如果把参数换成基本字段值呢?
我们曾探讨如果将函数签名改为:

1
buildRequest(String scheduledWarehouseDate, String inboundOrderNo)

那么这两个值就变成调用方的直接输入参数,调用者必须明确检查:

1
2
3
if (StrUtil.isEmpty(inboundOrderNo)) {
...
}

因为:

✅ 当你传递的是原始值(如String/int),使用它的代码就是最懂它语义的地方,调用者应承担责任。

🧩 4. int vs Integer:如何选择
类型 使用场景
int 业务默认值清晰、内部使用不需要表达“缺省”
Integer 业务字段可以为 null(未赋值、未选择)/ 与数据库字段对应时

举例:

1
2
3
4
5
public class UserDTO {
private Integer age; // 可以不填,允许 null
}

int sum = 0; // 内部统计逻辑,始终初始化

✅ 总结
函数设计中参数校验职责的判断,并非生硬划分,而是结合语义、职责、契约综合判断:

原则 描述
谁使用谁负责 使用字段的地方负责其有效性
谁输出谁负责 函数必须确保其输出可用性
最小信任原则 被调用方不应信任调用方输入,必要时做 fail-fast 校验
类型语义选择 Integer 适用于业务不确定性表达;int 用于纯粹逻辑场景

最重要的是:保持函数职责清晰,边界明确,遵循契约精神。

常用 Git 分支管理、提交、合并、同步等命令的速查表,适合日常开发参考。

阅读全文 »

RuoYi 项目模块划分与依赖传递总结

RuoYi 是一个经典的 Java 后台管理框架,模块化设计是其核心之一。如何合理划分模块、处理模块间依赖、明确工具类和服务的归属,对于构建可维护、易扩展的系统尤为关键。


🗂 模块划分原则

1️⃣ 按职责分层划分

模块 说明
ruoyi-common 通用工具、基础封装、无状态方法、第三方 SDK 集成
ruoyi-framework Web 框架封装:Spring Boot、Spring Security、MyBatis 等适配层
ruoyi-system 系统级服务模块:用户、角色、菜单、字典、OSS、邮件等
ruoyi-generator 代码生成器模块,用于 CRUD 快速生成
ruoyi-quartz 定时任务调度模块
ruoyi-job (可选)业务级定时任务逻辑
ruoyi-api 对外接口层(微服务版拆出)
ruoyi-admin Web 管理后台主入口

单体版:模块组合在一个应用内;
微服务版:模块拆分成独立微服务,通过 OpenFeign 调用。

2️⃣ 按依赖关系层次划分

  • common最底层,不依赖其他业务模块;
  • framework → 依赖 common
  • system → 依赖 commonframework
  • admin → 依赖 system,但不应反向依赖。
1
2
3
4
graph TD
common --> framework
framework --> system
system --> admin

🔗 模块间依赖传递策略

工具类依赖传递

  • ruoyi-common
    • 示例:DateUtils, BeanUtils, RedisUtils
    • 无状态、线程安全。
  • 其他模块通过依赖 common 引入工具类。

服务依赖传递

  • ruoyi-system
    • 示例:SysEmailService, SysOssService
    • 系统能力服务,提供统一业务入口。
  • 其他模块通过依赖 system 调用服务接口。

🚨 禁止反向依赖

比如 system 不应依赖 admin,否则会导致模块耦合,难以拆分。


🛠 工具类 vs 服务放置原则

类型 推荐模块 说明
工具类 common/utils 纯工具封装,无状态逻辑
封装 SDK common 第三方 SDK 初始化,如邮件、OSS 的底层封装
系统级服务 system/service 有状态、需读取配置表(如 sys_config
业务逻辑服务 业务模块 针对具体业务逻辑实现,如订单、库存等

🌟 示例

📧 邮件发送

  • EmailUtilsruoyi-common
  • SysEmailServiceruoyi-system
  • 调用:SysEmailService.sendEmail(to, subject, content)

📦 OSS 存储

  • OssUtilsruoyi-common
  • SysOssServiceruoyi-system
  • 调用:SysOssService.upload(file)

📖 总结

  • 🏗 模块职责单一,工具类与服务层分离;
  • 🚫 禁止模块间环形依赖
  • ✅ 通用封装放 common,系统能力放 system
  • ⚡ 微服务化后,system 可拆为独立服务(如 OSS 服务、邮件服务)。

📌 参考

🏋️‍♂️ 徒手极简训练 7 天计划(10 分钟进阶版)

🗓 训练频率

  • 每天 10~15 分钟
  • 适合基础版适应后进阶使用

🕒 时间建议

场景 推荐时间
☀️ 早晨 起床后 10 分钟(喝水后再做)
🌙 晚上 晚饭后适度训练(不影响睡眠)
📱 白天碎片时间 工作间隙站起来活动,1~2 分钟即可

📅 每日训练动作(循环 2 轮)

🗓 Day 1 / Day 4

  1. 站姿开合跳 🦘 - 30 秒
  2. 高抬腿 🚶‍♂️ - 30 秒
  3. 标准俯卧撑 💪 - 8~10 次
  4. 站立体前屈伸展 🧘 - 保持 20 秒

🗓 Day 2 / Day 5

  1. 深蹲 🦵 - 12 次
  2. 肩部绕环 🔄 - 前后各 10 次
  3. 站姿体侧伸展 ↔️ - 左右各 15 秒
  4. 平板支撑 💪 - 保持 20~30 秒

🗓 Day 3 / Day 6

  1. 原地快走或开合跳 🚶‍♀️ - 1 分钟
  2. 箭步后撤 🦵 - 每条腿 8~10 次
  3. 俯身肩部伸展 🧘 - 左右各保持 15 秒

🗓 Day 7(恢复+放松日)

  • 颈部放松(点头/摇头各 5 次)
  • 腰背放松(站姿猫牛式,左右转动腰部各 5 次)
  • 原地慢走 3 分钟

📌 注意事项

  1. 每天动作循环 2 轮,总计约 10~12 分钟
  2. 饭后建议间隔 30~60 分钟
  3. 可根据状态适当调整组数和时长
0%