Spring Boot中如何扁平化存储嵌套POJO数据?
问题描述
我有一个接收POJO的REST接口用于存储数据,相关代码如下:
@Service public class CassandraService { @Autowired MyReactiveCassandraRepository cassandraRepository; public Mono<String> save(Pojo pojo) { return cassandraRepository.save(pojo); } }
@Repository public interface MyReactiveCassandraRepository extends ReactiveCrudRepository<Pojo, String> { }
@Table public class Pojo { @PrimaryKey private String id; private String foo; private InnerPojo innerPojo; }
public class InnerPojo { String aaa; String bbb; }
我希望将数据扁平化存储(而非保留嵌套结构),预期的Cassandra表结构如下:
| id | foo | aaa | bbb |
|---|---|---|---|
目前我是通过复制一个FlattenPojo类并手动编写转换代码来实现,但想知道Spring Boot里有没有更优雅的方式?
解决方案
1. 直接利用Spring Data Cassandra的字段映射(无需额外POJO)
无需创建新类,直接在原Pojo上通过注解指定嵌套属性的列名,让Spring Data自动处理扁平化存储:
修改Pojo类:
@Table public class Pojo { @PrimaryKey private String id; private String foo; // 映射嵌套属性到扁平列 @Column("aaa") public String getAaa() { return innerPojo != null ? innerPojo.getAaa() : null; } @Column("bbb") public String getBbb() { return innerPojo != null ? innerPojo.getBbb() : null; } // 保留原嵌套字段,用于接收REST接口的嵌套数据 private InnerPojo innerPojo; // 省略所有字段的getter/setter }
这种方式下,Spring Data Cassandra会自动将innerPojo的属性映射到Cassandra的扁平列中,同时原Pojo仍能正常接收接口传入的嵌套数据。
2. 实现自定义类型转换器
通过Spring的Converter接口,让框架自动处理Pojo与扁平存储实体的转换,避免手动编写重复代码:
第一步:定义内部存储用的扁平实体
// 仅作为Cassandra存储载体,无需对外暴露 public class FlattenedPojoEntity { @PrimaryKey private String id; private String foo; private String aaa; private String bbb; // 省略构造器、getter/setter }
第二步:编写转换逻辑
@Component public class PojoToFlattenedEntityConverter implements Converter<Pojo, FlattenedPojoEntity> { @Override public FlattenedPojoEntity convert(Pojo source) { FlattenedPojoEntity entity = new FlattenedPojoEntity(); entity.setId(source.getId()); entity.setFoo(source.getFoo()); if (source.getInnerPojo() != null) { entity.setAaa(source.getInnerPojo().getAaa()); entity.setBbb(source.getInnerPojo().getBbb()); } return entity; } } // 如需查询后转换回原Pojo,添加反向转换器 @Component public class FlattenedEntityToPojoConverter implements Converter<FlattenedPojoEntity, Pojo> { @Override public Pojo convert(FlattenedPojoEntity source) { Pojo pojo = new Pojo(); pojo.setId(source.getId()); pojo.setFoo(source.getFoo()); InnerPojo inner = new InnerPojo(); inner.setAaa(source.getAaa()); inner.setBbb(source.getBbb()); pojo.setInnerPojo(inner); return pojo; } }
第三步:修改Repository与Service
@Repository public interface FlattenedPojoRepository extends ReactiveCrudRepository<FlattenedPojoEntity, String> { }
@Service public class CassandraService { @Autowired FlattenedPojoRepository repository; public Mono<String> save(Pojo pojo) { return repository.save(pojo) .map(FlattenedPojoEntity::getId); } }
Spring会自动识别并触发转换器,无需手动调用转换方法。
3. 用ModelMapper简化对象转换
如果必须保留原POJO与扁平类的分离(比如原POJO需严格匹配接口契约),可以用ModelMapper自动处理属性映射:
第一步:引入依赖(Maven)
<dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>3.1.1</version> </dependency>
第二步:配置ModelMapper
@Configuration public class ModelMapperConfig { @Bean public ModelMapper modelMapper() { ModelMapper mapper = new ModelMapper(); // 配置嵌套属性到扁平字段的映射规则 mapper.typeMap(Pojo.class, FlattenPojo.class) .addMapping(p -> p.getInnerPojo().getAaa(), FlattenPojo::setAaa) .addMapping(p -> p.getInnerPojo().getBbb(), FlattenPojo::setBbb); return mapper; } }
第三步:在Service中使用
@Service public class CassandraService { @Autowired MyReactiveCassandraRepository repository; @Autowired ModelMapper modelMapper; public Mono<String> save(Pojo pojo) { FlattenPojo flattened = modelMapper.map(pojo, FlattenPojo.class); return repository.save(flattened); } }
内容的提问来源于stack exchange,提问作者PatPanda
相关产品推荐
相关产品推荐

