使用Spring Data MongoDB时如何返回不可变DTO?
解决Spring Data MongoDB返回不可变DTO的问题
问题原因
你遇到的报错是因为Spring Data MongoDB默认尝试用无参构造函数创建DTO实例,然后通过Setter方法为字段赋值,但你的ItemBase是不可变类(字段为final且无Setter),因此无法完成赋值操作。
解决方案
Spring Data MongoDB支持通过构造函数映射查询结果到不可变DTO,无需像JPA那样写select new语法,只需按以下步骤调整:
1. 确保不可变DTO的构造函数参数与查询字段匹配
检查ItemBase的带参构造函数,参数名称或顺序要与你查询返回的字段严格对应:
public class ItemBase { private final String itemDetail; private final Integer itemScore; // 带参构造函数:参数名和Item实体的字段名完全一致 public ItemBase(String itemDetail, Integer itemScore) { this.itemDetail = itemDetail; this.itemScore = itemScore; } // 可以保留无参构造,但Spring会优先匹配带参构造(满足条件时) public ItemBase() { this.itemDetail = null; this.itemScore = null; } // 仅提供Getter方法 public String getItemDetail() { return itemDetail; } public Integer getItemScore() { return itemScore; } }
2. 配置编译时保留参数名称(关键)
Java默认不会在字节码中保留构造函数/方法的参数名称,Spring Data无法通过参数名匹配字段。需要在编译时添加-parameters参数:
- Maven:在
pom.xml的maven-compiler-plugin中配置
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
- Gradle:在
build.gradle中添加
compileJava { options.compilerArgs << '-parameters' }
3. 调整Repository的@Query注解
保持原有的@Query配置,Spring Data会自动匹配带参构造函数创建ItemBase实例:
public interface ItemRepo extends MongoRepository<Item, String> { @Query(value = "{ 'itemId' : ?0 }", fields = "{ 'itemDetail' : 1, 'itemScore' : 1 }") ItemBase findOneByItemIdIncludeEmbeddedFields(String itemId); }
备选方案:通过投影接口实现(更简洁)
如果不需要自定义构造函数逻辑,也可以用Spring Data的投影接口替代不可变类,自动生成实现类:
public interface ItemBaseProjection { String getItemDetail(); Integer getItemScore(); }
然后Repository方法直接返回该接口:
@Query(value = "{ 'itemId' : ?0 }", fields = "{ 'itemDetail' : 1, 'itemScore' : 1 }") ItemBaseProjection findOneByItemIdIncludeEmbeddedFields(String itemId);
内容的提问来源于stack exchange,提问作者ban_ana
相关产品推荐
相关产品推荐

