這篇文章在 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()); }