参数传递核心是明确“传什么、谁组织、边界在哪”,应使用语义化DTO封装入参,按业务动因分层拆分,逐层转换隔离风险,并以配置驱动替代动态参数。

复杂业务场景下,参数传递的核心不是“怎么传”,而是“传什么、谁来组织、边界在哪”。关键在于把混乱的输入收敛成清晰、可维护、有语义的数据结构,同时守住层与层之间的职责边界。
用 DTO 封装入参,别拼 Map 或堆参数列表
多个业务字段(比如订单创建:商品ID、数量、优惠券码、收货地址、支付方式、是否开票)直接塞进方法签名,或用 Map
- DTO 是专为传输设计的轻量对象,只含字段+getter/setter,不带逻辑,命名直白(如 OrderCreateRequest)
- 它天然支持校验(配合 @Valid)、脱敏(不暴露密码/身份证)、版本演进(加字段不影响老调用)
- 比 @Param 注解更适合多于 3 个参数的场景,避免参数顺序错位、类型混淆等低级但致命的问题
按业务动因拆分参数对象,而不是按技术层级
一个接口不该承载所有变化点。比如促销结算,用户等级、商品类目、渠道来源、活动类型、库存状态都在变——全塞进一个 DTO 里,每次新增规则就得改这个类,违反开闭原则。
- 可考虑组合式设计:主 DTO 持有 StrategyContext、PromotionScope、InventoryLockPolicy 等子对象
- 每个子对象代表一类可独立演化的业务维度,新增一种促销类型,只需扩展 PromotionScope 的实现,不碰主结构
- 这背后对应策略模式+参数对象分层,让“变”和“不变”在代码结构上就区分开
明确参数所有权和生命周期,避免跨层污染
前端传来的原始参数 ≠ 服务层内部使用的参数。中间往往要经过转换、校验、补全、降噪。
立即学习“Java免费学习笔记(深入)”;
- Controller 层接收原始 DTO(如 UserRegisterRequest),做基础格式校验和非空检查
- Service 层应使用语义更明确的内部参数对象(如 RegistrationContext),它可能已补全 IP、设备指纹、邀请码归属关系等上下文
- DAO 层绝不直接用前端 DTO,必须转为符合数据模型的 QueryCondition 或 Command 对象
- 这种逐层转化不是冗余,是隔离风险:前端字段删了、重命名了,只影响 Controller 到 Service 的映射,不会波及数据库操作
对“动态参数”保持警惕,优先用配置驱动而非开放参数
有些场景看似需要灵活传参(如自定义筛选条件、运行时表达式),但放开任意 key-value 容易失控。
- 能用枚举限定的,就不用字符串(如 status=“paid” 改成 PaymentStatus.PAID)
- 需动态过滤的,提供预设 filterType + value 组合(如 filterType=“price_range”, value=“100-500”),而非让用户拼 SQL 片段
- 真有执行脚本需求,走独立的安全沙箱服务,不混在主业务参数流里


















