国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

對于springframework的mongoTemplate擴展自定義的分享

2019-11-08 20:42:16
字體:
來源:轉載
供稿:網友

之前對于sPRing的mongoTemplate真的是有點又愛又恨,由于它對mongodb的驅動做了一層封裝,使得在開發的時候方便了許多,但是它的語法和mongo的原生js有很大不同,有時候在mongo官方文檔里的API接口很多時候在mongoTemplate中的使用完全不一樣,導致有些時候用的很別扭,而且一些語句完全不知道怎么去轉換為template的語法。不過最近的兩次使用經歷使得我對mongoTemplate有了一些改觀。

第一個就是mongoTemplate自身的criteria.where沒有>和<的操作,也就是對mongo的一條記錄自身的兩個字段進行比較。mongo語句如下:

db.whereColl.find({$where: "this.b > this.a"})

當時研究和許久,最后實在沒招了,扒源碼找出了它的Criteria實現,下面是它的源碼實現:

/** * Creates a criterion using the {@literal $elemMatch} Operator *  * @see http://docs.mongodb.org/manual/reference/operator/query/elemMatch/ * @param c * @return */public Criteria elemMatch(Criteria c) {   criteria.put("$elemMatch", c.getCriteriaObject());   return this;}
/** * Creates an 'and' criteria using the $and operator for all of the provided criteria. * <p> * Note that mongodb doesn't support an $and operator to be wrapped in a $not operator. * <p> *  * @throws IllegalArgumentException if {@link #andOperator(Criteria...)} follows a not() call directly. * @param criteria */public Criteria andOperator(Criteria... criteria) {   BasicDBList bsonList = createCriteriaList(criteria);   return registerCriteriaChainElement(new Criteria("$and").is(bsonList));}
private BasicDBList createCriteriaList(Criteria[] criteria) {   BasicDBList bsonList = new BasicDBList();   for (Criteria c : criteria) {      bsonList.add(c.getCriteriaObject());   }   return bsonList;}
public DBObject getCriteriaObject() {   if (this.criteriaChain.size() == 1) {      return criteriaChain.get(0).getSingleCriteriaObject();   } else if (CollectionUtils.isEmpty(this.criteriaChain) && !CollectionUtils.isEmpty(this.criteria)) {      return getSingleCriteriaObject();   } else {      DBObject criteriaObject = new BasicDBObject();      for (Criteria c : this.criteriaChain) {         DBObject dbo = c.getSingleCriteriaObject();         for (String k : dbo.keySet()) {            setValue(criteriaObject, k, dbo.get(k));         }      }      return criteriaObject;   }}
protected DBObject getSingleCriteriaObject() {   DBObject dbo = new BasicDBObject();   boolean not = false;   for (String k : this.criteria.keySet()) {      Object value = this.criteria.get(k);      if (not) {         DBObject notDbo = new BasicDBObject();         notDbo.put(k, value);         dbo.put("$not", notDbo);         not = false;      } else {         if ("$not".equals(k) && value == null) {            not = true;         } else {            dbo.put(k, value);         }      }   }   if (!StringUtils.hasText(this.key)) {      if (not) {         return new BasicDBObject("$not", dbo);      }      return dbo;   }   DBObject queryCriteria = new BasicDBObject();   if (!NOT_SET.equals(isValue)) {      queryCriteria.put(this.key, this.isValue);      queryCriteria.putAll(dbo);   } else {      queryCriteria.put(this.key, dbo);   }   return queryCriteria;}
private void setValue(DBObject dbo, String key, Object value) {   Object existing = dbo.get(key);   if (existing == null) {      dbo.put(key, value);   } else {      throw new InvalidMongoDbApiUsageException("Due to limitations of the com.mongodb.BasicDBObject, "            + "you can't add a second '" + key + "' expression specified as '" + key + " : " + value + "'. "            + "Criteria already contains '" + key + " : " + existing + "'.");   }}通過上面的源碼可以知道,mongoTemplate的語法轉換是通過構建一個DBObject,然后將查詢語法轉換為mongo的java驅動的語法,也是接近于原生的語法。

知道了這個,稍微對com.mongodb包有些經驗的都應該知道要怎么去操作了,我們通過復寫getCriteriaObject方法來實現自定義查詢語句,突破mongoTemplate的限制,我的實現如下:

    public ListResponse<AObject> loadAObjectList(String aId, String bId, int start, int limit) {        ListResponse<AObject> AObjectListResp = new ListResponse<AObject>();        Criteria criteria = new Criteria() {            @Override            public DBObject getCriteriaObject() {                DBObject obj = new BasicDBObject();                obj.put("$where", "this.groupNum > this.joinedNum");                return obj;            }        };        Query query = Query.query(criteria);        query.addCriteria(Criteria.where("members").nin(bId).and("aId").is(aId)).with(new Sort(Sort.Direction.DESC, "gmtCreated")).skip((start-1) * limit).limit(limit);        List<AObject> AObjectList = template.find(query, AObject.class);        long count = template.count(new Query(criteria).addCriteria(.where("members").nin(bId).and("aId").is(aId)), AObject.class);        return AObjectListResp.fill(ResponseCode.SUCCESS, "success", AObjectList, count, count > start * limit);    }上面我們通過復寫相關方法來自定義Criteria語法,而另一個事件是今天的一個項目,需要從mongo中隨機取出一定數量的文檔,我們知道mongo在3.2版本之后對此加入了一個官方的api,我們可以使用aggregate管道的$sample來讀取文件,mongo語法如下:

db.users.aggregate(   [ { $sample: { size: 3 } } ])我看了mongotemple的aggregate相關API,發現它的API只有以下幾個,即便是升級到最新的1.10.0-RELEASE版本也是如此,最后我想起上面的自定義擴展,于是,又去吭哧吭哧地翻看源代碼,首先:
template.aggregate(Aggregation.newAggregation(Aggregation.match(Criteria),.....),....);我發現它的語法條件都是通過Aggregation.XXX來操作的,于是,我打開Aggregation.XXX的源碼:

/** * Creates a new {@link MatchOperation} using the given {@link Criteria}. *  * @param criteria must not be {@literal null}. * @return */public static MatchOperation match(Criteria criteria) {   return new MatchOperation(criteria);}
/** * Creates a new {@link LimitOperation} limiting the result to the given number of elements. *  * @param maxElements must not be less than zero. * @return */public static LimitOperation limit(long maxElements) {   return new LimitOperation(maxElements);}我發現它是構建不同的XXXOperation,于是,我打開MatchOperation和LimitOperation:

public class MatchOperation implements AggregationOperation {   private final CriteriaDefinition criteriaDefinition;   /**    * Creates a new {@link MatchOperation} for the given {@link CriteriaDefinition}.    *     * @param criteriaDefinition must not be {@literal null}.    */   public MatchOperation(CriteriaDefinition criteriaDefinition) {      Assert.notNull(criteriaDefinition, "Criteria must not be null!");      this.criteriaDefinition = criteriaDefinition;   }   /*     * (non-Javadoc)    * @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)    */   @Override   public DBObject toDBObject(AggregationOperationContext context) {      return new BasicDBObject("$match", context.getMappedObject(criteriaDefinition.getCriteriaObject()));   }}
public class LimitOperation implements AggregationOperation {   private final long maxElements;   /**    * @param maxElements Number of documents to consider.    */   public LimitOperation(long maxElements) {      Assert.isTrue(maxElements >= 0, "Maximum number of elements must be greater or equal to zero!");      this.maxElements = maxElements;   }   /*     * (non-Javadoc)    * @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)    */   @Override   public DBObject toDBObject(AggregationOperationContext context) {      return new BasicDBObject("$limit", maxElements);   }}到這兒,我發現最終,它的操作也是落到了BasicDBObject上面,并且都是通過繼承AggregationOperation來實現的,于是我照著葫蘆畫瓢,自己自定義了一個SampleOperation類:

public class SampleOperation implements AggregationOperation {    private final long maxElements;    /**     * @param maxElements Number of documents to consider.     */    public SampleOperation(long maxElements) {        Assert.isTrue(maxElements >= 0, "Maximum number of elements must be greater or equal to zero!");        this.maxElements = maxElements;    }    /*    * (non-Javadoc)    * @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)    */    @Override    public DBObject toDBObject(AggregationOperationContext context) {        return new BasicDBObject("$sample",  new BasicDBObject("size", maxElements));    }}通過這兩次經歷,我發現mongoTemplate雖然語法上和原生的語法有些不同之處,但是它在設計之初充分地考慮到了開發的自定義擴展。

上面是我個人的一些小小的心(慘)得(通)經(教)驗(訓),希望能夠對大家有些幫助。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 龙州县| 即墨市| 凤城市| 广昌县| 嘉鱼县| 大石桥市| 双流县| 平顺县| 桐柏县| 志丹县| 荃湾区| 长阳| 通辽市| 香港| 滨州市| 祁连县| 德格县| 牟定县| 新龙县| 随州市| 阜平县| 拉萨市| 嘉荫县| 滦平县| 镇平县| 东乡族自治县| 乃东县| 福清市| 特克斯县| 宜章县| 葵青区| 巨鹿县| 准格尔旗| 武冈市| 宜昌市| 双流县| 西平县| 修水县| 启东市| 黄骅市| 绵竹市|