You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot如何实现类似projections的低成本灵活DTO构建?

结论

可以直接定义仅包含所需字段的接口作为方法参数或返回值,这是Spring Boot生态下实现类投影效果、减少DTO模板代码的最优方案之一,除此之外还有多个低成本实现方案可供选择:


方案1:接口投影(零实现成本,适配Spring Data Projections使用习惯)

Spring MVC内置的Jackson序列化/反序列化模块原生支持接口类型处理,你不需要编写任何接口实现类、getter/setter模板代码,仅需要定义携带对应get方法的接口即可:

// 仅返回id和登录名的投影接口
public interface UserLoginProjection {
    UUID getId();
    String getLogin();
}

// 包含id、登录名、邮箱的投影接口
public interface UserLoginEmailProjection {
    UUID getId();
    String getLogin();
    String getEmail();
}

直接在Controller中替换原有DTO类即可正常使用:

@RestController("/users")
public class UserController {
  @PutMapping
  public UserLoginProjection someRequest(@RequestBody UserLoginEmailProjection user) {
      // 直接调用接口的get方法即可获取请求参数,返回值也可直接返回投影实例
  }
}

如果和Spring Data JPA结合使用,还可以直接将投影接口作为Repository查询方法的返回值,省去实体到DTO的手动字段拷贝步骤:

public interface UserRepository extends JpaRepository<User, UUID> {
    // 动态返回指定类型的投影
    <T> T findById(UUID id, Class<T> projectionType);
}

需要新增字段时,仅需要在对应接口中新增对应get方法即可,维护成本极低。


方案2:Java Record类(Java 16+推荐,支持扩展能力)

如果你需要给DTO添加字段校验、自定义逻辑等能力,接口投影的灵活性不足,可以使用Java 16引入的Record类替代传统DTO类,无需手动编写getter、setter、构造方法、equals/hashCode等模板代码:

// 仅返回id和登录名的Record
public record UserLoginRecord(UUID id, String login) {}

// 包含id、登录名、邮箱的Record
public record UserLoginEmailRecord(UUID id, String login, String email) {}

用法和普通DTO类完全一致,新增字段仅需要在构造参数中添加对应项即可,同时支持直接添加@NotBlank等校验注解,适配更多业务场景。


方案3:动态映射工具(适合多投影场景复用转换逻辑)

如果业务中存在大量不同字段组合的投影场景,不想重复定义大量接口/Record,可以结合MapStruct、ModelMapper等映射工具,统一配置实体到不同投影的转换规则,仅需要定义投影类/接口,转换逻辑由工具自动生成,进一步降低重复编码成本。


内容的提问来源于stack exchange,提问作者Igor Chestnov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:06:03