这篇文章在 spring data mongodb基础篇 的基础上作的扩展java
思路:实现org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener<Object>中的onBeforeConvert()方法,mongodb在保存业务对象以前,会先把业务对象转化为DBObject,经过日志能够发现 onBeforeConvert() 在onBeforeSave()以前调用:因此咱们能够在保存对象以前处理关联对象,覆盖 onBeforeConvert() 方法。spring
更通用的作法是覆盖onApplicationEvent(),这个方法在全部的事件以前都会执行,能够根据不一样的事件类型作不一样的操做,咱们甚至还能够实现级联删除操做。mongodb
com.wss.lsl.pay.demo.model.User 实体对象加数据库
@DBRef // mongodb的注解,文档之间创建关联关系,能够认为是关系型数据库中的外键 @CascadeSave // 自定义的注解 @Field("card") private Card card; // getter/setter
com.wss.lsl.pay.demo.model.Card实体对象:app
@Document(collection = "card") public class Card { @Id private String id; // mongodb的主键 private String cardNo; // 卡号 // getter/setter }
自定义的注解com.wss.lsl.pay.demo.common.annotation.CascadeSaveide
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface CascadeSave { }
com.wss.lsl.pay.demo.listener.CascadeSaveMongoEventListener实现了 AbstractMongoEventListener单元测试
package com.wss.lsl.pay.demo.listener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; import org.springframework.util.ReflectionUtils; import com.mongodb.DBObject; import com.wss.lsl.pay.demo.common.callback.CascadeSaveCallback; public class CascadeSaveMongoEventListener extends AbstractMongoEventListener<Object> { @Autowired private MongoTemplate mongoTemplate; @Override public void onBeforeConvert(Object source) { ReflectionUtils.doWithFields(source.getClass(), new CascadeSaveCallback(source, mongoTemplate)); super.onBeforeConvert(source); } }
com.wss.lsl.pay.demo.common.callback.CascadeSaveCallback测试
package com.wss.lsl.pay.demo.common.callback; import java.lang.reflect.Field; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.util.ReflectionUtils; import com.wss.lsl.pay.demo.common.annotation.CascadeSave; public class CascadeSaveCallback implements ReflectionUtils.FieldCallback { private Object source; private MongoTemplate mongoTemplate; public CascadeSaveCallback(Object source, MongoTemplate mongoTemplate) { super(); this.source = source; this.mongoTemplate = mongoTemplate; } @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { ReflectionUtils.makeAccessible(field); if(field.isAnnotationPresent(DBRef.class) && field.isAnnotationPresent(CascadeSave.class)){ final Object fieldValue = field.get(source); if(fieldValue != null){ FieldCallback fc = new FieldCallback(); ReflectionUtils.doWithFields(fieldValue.getClass(), fc); mongoTemplate.save(fieldValue); } } } }
com.wss.lsl.pay.demo.common.callback.FieldCallbackthis
package com.wss.lsl.pay.demo.common.callback; import java.lang.reflect.Field; import org.springframework.data.annotation.Id; import org.springframework.util.ReflectionUtils; public class FieldCallback implements ReflectionUtils.FieldCallback { private boolean isFound; @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { ReflectionUtils.makeAccessible(field); if (field.isAnnotationPresent(Id.class)) { isFound = true; } } public boolean isFound() { return isFound; } }
spring的配置文件applicationContext.xml加.net
<!-- cascade operation --> <bean class="com.wss.lsl.pay.demo.listener.CascadeSaveMongoEventListener" />
单元测试:UserRepositoryTest中添加测试方法
// 测试级联操做 @Test public void testCascade() { User user = new User("有会员卡的用户", 20); Card card = new Card("1323232"); user.setCard(card); // 咱们只保存了user userRepository.save(user); // 校验card确实保存进去了:card产生了id Assert.assertNotNull(card.getId()); }