当前位置: 首页 > news >正文

Spring Boot + MyBatis 多模块项目中,如何优雅完成一个增量需求

摘要

在老系统中做需求,最怕的不是写代码,而是不清楚应该改哪里、复用哪里、绕开哪里。本文结合一个续期管理后台中的“规则中心配置页”需求,聊聊在 Spring Boot + MyBatis 多模块项目里,如何用较小改动完成一次稳定的增量开发。

1. 背景

很多企业项目不是从零开始的,而是在已有系统上不断迭代。常见结构大概是:
project-root
├── project-api
├── project-common
├── project-core
├── project-provider
├── project-server
└── project-web
这类项目通常有几个特点:
Controller 层在 web 模块;
业务 Service 在 core 模块;
DTO、Entity、Param 在 api 模块;
通用枚举、工具类在 common 模块;
外部系统调用或消息处理在 provider/server 模块;
MyBatis Mapper 和 XML 通常集中在 core。
如果新需求一上来就大改底层逻辑,风险会非常高。更稳妥的方式是:先定位现有链路,再基于现有架构做增量封装。

2. 增量需求的拆解方式

以“新增一个配置页”为例,页面可能包含:
配置列表查询;
新增配置;
删除配置;
批量提交;
操作历史;
异常清单下载;
权限控制。
后端可以拆成以下几层:
Controller

Application Service

Domain / Legacy Service

Mapper / External Provider
关键点是:新 Service 不一定要重写业务逻辑,而是作为“编排层”存在。
例如:

publicinterfaceDataConfigService{List<ProductOption>listProductOptions(Stringkeyword);voidaddConfig(IntegerproductId,StringproductName,LongoperatorId);voiddeleteConfig(IntegerproductId,LongoperatorId);BatchResultbatchRepair(Stringids,StringoperatorNo,StringoperatorName);PageResult<ImportRecordDTO>pageRecords(RecordQueryquery);}

这个接口并不关心底层数据到底来自老表、新表、外部接口还是消息处理链路。它的职责是把页面需要的能力整理成稳定接口。

3. Controller 层只做三件事

在老项目里,Controller 很容易越写越厚。我的经验是尽量让 Controller 只做三件事:
接收参数;
获取当前操作人;
调用 Service 并返回统一结果。
示例:

@PostMapping("/config/add")publicResult<Void>addConfig(@RequestBodyConfigRequestrequest,HttpServletRequestservletRequest){Employeeemployee=getCurrentEmployee(servletRequest);dataConfigService.addConfig(request.getProductId(),request.getProductName(),Long.valueOf(employee.getId()));returnResult.success();}

这样做的好处是清晰:
参数校验在 Service 中统一处理;
操作人信息不散落在各处;
Controller 不感知底层业务细节;
后续单测更容易写。

4. 复用旧逻辑,而不是复制旧逻辑

老系统里常常已经有一些能力,比如:
根据投保单号查询主数据;
更新保单状态;
调用外部系统补齐数据;
写操作日志;
发送消息通知;
查询配置。
新增功能时,优先考虑“调用已有 Service”,而不是把旧代码复制一份过来。
错误示例:

// 把旧逻辑复制到新 Service 中,后续两边都要维护privatevoidrepairData(Longid){// 一大段复制来的老逻辑}

更好的方式:

privatevoidrepairData(Longid){legacyRepairService.repairById(id);}如果旧逻辑粒度太粗,可以在外层做适配:privatevoidrepairOne(Longid){try{legacyService.repair(id);}catch(Exceptione){thrownewBusinessException(normalizeMessage(e.getMessage()));}}

这样新增功能就变成“业务编排”,不是“底层重写”。

5. 批处理要有记录和失败明细

批量提交类需求不要只返回一句“处理完成”。更实用的模型是:
导入记录表
├── 操作类型
├── 操作人
├── 总数
├── 成功数
├── 失败数
├── 状态
└── 操作时间

失败明细表
├── 记录ID
├── 业务单号
└── 失败原因
批处理伪代码:

privateBatchResultexecuteBatch(List<Long>ids,Processorprocessor){ImportRecordrecord=createRecord(ids.size());intsuccess=0;List<ImportError>errors=newArrayList<>();for(Longid:ids){try{processor.process(id);success++;}catch(Exceptione){errors.add(buildError(record.getId(),id,e.getMessage()));}}saveErrors(errors);updateRecord(record,success,errors.size());returnbuildResult(record);}

这个设计有两个明显优势:
用户知道每次操作的结果;
失败数据可以下载后继续排查。

6. 小结

在多模块老系统中做增量需求,重点不是“写更多代码”,而是“把新功能安放在合适的位置”。
建议遵循几个原则:
Controller 保持薄;
新增 Service 做编排;
复用旧业务链路;
Mapper 只承载必要查询;
批处理必须有历史记录;
权限点跟页面和按钮保持一致;
不做无关重构。
老系统改造最重要的是稳。能小步扩展,就不要大刀阔斧。

http://www.jsqmd.com/news/1079345/

相关文章:

  • 运维转大模型:把学习路线变成作品集
  • 大模型聚合 API 全网测速实测:延迟瓶颈拆解与商用平台落地对比
  • 统计短视频东方美学穿搭播放数据,算法计算国风内容传播流量增益值。
  • 3分钟掌握WinAsar:Windows平台最轻量asar文件管理工具终极指南
  • 2026全栈信创选型深度指南:AI Agent兼容国产芯片的架构博弈与提效实战
  • 【计算机毕业设计案例】基于 SpringBoot 的高校学术活动管理与交流平台设计与实现基于 Java 与 SpringBoot 的高校学术交流平台设计与实现(程序+文档+讲解+定制)
  • 【极速入门数模电路】双稳态/单稳态/无稳态电路
  • 小模型不一定要从头练!普林斯顿研究:预算有限剪枝完胜,但真正的优势藏在稀疏里
  • 微软推出两大开发工具:Coreutils 统一命令体验,Dev Config 快速配置开发环境
  • 2026年梳子选购指南:这5个品牌专业度实测揭晓
  • 高防IP一个月6500还只是起步?聊聊小团队能用的DDoS防护方案
  • 5分钟掌握ncmdump:终极网易云音乐NCM格式解密转换指南
  • Python的__enter__中的处理事务
  • Prime Day来袭!ZDNET编辑精选90多款优惠,7款iPhone小工具超值折扣
  • 2026 AI/LLM黑话速通:Prefill、RLVR、GraphRAG,进阶概念怎么用?从小白到听懂面试官在说什么(下)
  • 构建企业级Java接口测试框架:从契约驱动到CI/CD集成
  • TSMaster 双月硬核迭代!4月新增音视频追踪,5月引入Codex Skills,SOME/IP精控再升级
  • 告别繁琐邮件客户端:如何用Roundcube Mail打造个人专属网页邮箱系统
  • 移动应用逆向工程与Hook实战:从原理到wxhelper工具实现
  • 浦东新区新高一语文补课班学习技巧:文言积累、现代文提升测评
  • 做工控品质7年掏心窝分享:选串口屏别乱踩坑
  • 推荐题目:洛谷 P1049 [NOIP 2001 普及组] 装箱问题
  • 天津GEO代理公司口碑排行 高好评服务商盘点
  • 智能钢琴指法生成器:如何用动态规划算法优化演奏体验
  • WindowResizer终极指南:如何轻松掌控任意窗口尺寸的完整教程
  • Go+Selenium构建企业级测试框架:架构设计与实战优化
  • 免费虚拟桌面伴侣:5个功能让你打造独一无二的二次元伙伴
  • 工程化工具链
  • Andromeda:爱奇艺开源的 Android 组件通信框架
  • Java实现密码安全存储:SHA-256加盐哈希原理与实战