当前位置: 首页 > 工具软件 > Morphia > 使用案例 >

使用Morphia操作MongoDB

呼延运恒
2023-12-01

项目环境:SpringBoot + SpringClound + JDK8

1.添加Morphiade的Maven依赖

    <dependency>
      <groupId>org.mongodb.morphia</groupId>
      <artifactId>morphia</artifactId>
      <version>1.1.0</version>
    </dependency>

2.启动文件bootstrap.profiles中添加mongoDB配置

mongo.uri=mongodb://microschool:microschool@192.168.3.252:27017/micro-school?authSource=micro-school
mongo.dbName=micro-school

3.MongoDB属性读取及配置类

package com.h.mongo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MongoProperties {
    @Value("${mongo.uri:}")
    protected String uri;
    @Value("${mongo.dbName:}")
    protected String dbName;

    public String getUri() {
        return uri==null?null:uri.trim();
    }
    public void setUri(String uri) {
        this.uri = uri;
    }
    public String getDbName() {
        return dbName==null?null:dbName.trim();
    }
    public void setDbName(String dbName) {
        this.dbName = dbName;
    }
}
package com.h.mongo;

import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientURI;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.Morphia;
import org.mongodb.morphia.annotations.Entity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.PreDestroy;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Configuration
public class MongoAutoConfiguration {
    protected Logger log = LoggerFactory.getLogger(getClass());  

    @Autowired
    private MongoProperties mongoProperties;

    @Bean(name = "dsForRW")
    public Datastore dsForRW() throws Exception {
        MongoClient mongoClient = createInstance(mongoProperties);
        Datastore dsForRWMdt = morphia().createDatastore(mongoClient, mongoProperties.getDbName());
        afterCreateDs(dsForRWMdt);
        return dsForRWMdt;
    }

    @PreDestroy
    public void close(){
        log.info("mongoClient is destroy");
    }

    private void afterCreateDs(Datastore dsForRW)  throws UnknownHostException {
        try {
            dsForRW.ensureIndexes();
            dsForRW.ensureCaps();
//          BasicDBObject keys = new BasicDBObject();
//          keys.put("link", 1);
//          keys.put("shortLink", 1);

//          DBCollection dbCollection = ds.getCollection(ShortLink.class);
//          dbCollection.createIndex(keys);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private MongoClient createInstance(MongoProperties mongoProperties)  throws UnknownHostException {

        MongoClientOptions.Builder builder = MongoClientOptions.builder();
        builder.socketKeepAlive(true);
        builder.connectTimeout(5000);
        builder.socketTimeout(0);
//      builder.maxWaitTime(60000);
        builder.heartbeatFrequency(2000);// 心跳频率

        MongoClientURI clientURI = new MongoClientURI(mongoProperties.getUri(),builder); 
        MongoClient mongoClient = new MongoClient(clientURI);
        if(StringUtils.isEmpty(mongoProperties.getDbName())){
            mongoProperties.setDbName(clientURI.getDatabase());
        }
        return mongoClient;
    }

    private Morphia morphia() {
        //
        Morphia morphia = new Morphia();
        // 手动加载
        if (0 == morphia.getMapper().getMappedClasses().size()) {
//          morphia.map(com.dachen.shorturl.domains.ShortLink.class);
        }
        Set<Class>clazzSet = this.getAllEntity("com.dachen");
        if(clazzSet!=null && clazzSet.size()>0){
            morphia.map(clazzSet);
        }
        morphia.getMapper().getConverters().addConverter(BigDecimalConverter.class);
        return morphia;
    }

    @SuppressWarnings("rawtypes")
    private Set<Class> getAllEntity(String packageName){
        List<Class<?>> returnClassList = ClassUtil.getClasses(packageName) ;
        if(returnClassList==null || returnClassList.isEmpty()){
            return null;
        }
        Set<Class>clazzSet = new HashSet<>();
        for(Class<?> clazz:returnClassList){
            Entity entity = clazz.getAnnotation(Entity.class);
            if(entity!=null){
                log.info("loading mongo entity:{},table:{}",clazz.getName(),entity.value());
                clazzSet.add(clazz);
            }
        }
        return clazzSet;
    }

}

4.Morphia操作MongoDB的工具类

package com.h.mongo;

import com.mongodb.*;
import org.bson.types.ObjectId;
import org.mongodb.morphia.AdvancedDatastore;
import org.mongodb.morphia.mapping.Mapper;
import org.mongodb.morphia.query.Query;
import org.mongodb.morphia.query.UpdateOperations;
import org.mongodb.morphia.query.UpdateResults;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

@Component
public class MongoCommonDAO {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Resource(name = "dsForRW")
    protected AdvancedDatastore dsForRW;


    public <T> T getByObjectId(final Class<?> clazz,ObjectId id){
        @SuppressWarnings("unchecked")
        Query<T> query = (Query<T>) dsForRW.createQuery(clazz);
        query.filter(Mapper.ID_KEY,id);
        return query.get();
    }

    public <T> T getByPK(final Class<?> clazz,String pk){
        Query <T> query = this.createQuery(clazz, pk);
        return query.get();
    }

    public <T> T findAndModifyByPK(final Class<?> clazz,String pk,DBObject update){
        Query <T> query = this.createQuery(clazz, pk);
        UpdateOperations<T> ops = this.createUpdateOperations(clazz, update);
        return dsForRW.findAndModify(query, ops);
    }

    public <T> T findAndModify(final Class<?> clazz,DBObject filter,DBObject update){
        Query<T> query = this.createQuery(clazz, filter);
        UpdateOperations<T> ops = this.createUpdateOperations(clazz,update);
        return dsForRW.findAndModify(query, ops);
    }

    public <T> T findAndModifyOrCreate(final Class<?> clazz,DBObject filter,DBObject update){
        Query<T> query = this.createQuery(clazz, filter);
        UpdateOperations<T> ops = this.createUpdateOperations(clazz,update);
        return dsForRW.findAndModify(query, ops,false, true);
    }

    public <T> UpdateResults update(final Class<?> clazz,DBObject filter,DBObject update)
    {
        Query<T> query = this.createQuery(clazz, filter);
        UpdateOperations<T> ops = this.createUpdateOperations(clazz, update);
        return dsForRW.update(query, ops);
    }

    @SuppressWarnings("unchecked")
    public <T> UpdateResults addToArray(final Class<?> clazz,DBObject filter,String fieldExpr, List<?> values, boolean addDups)
    {
        Query<T> query = this.createQuery(clazz, filter);
        UpdateOperations<T> ops = (UpdateOperations<T>) dsForRW.createUpdateOperations(clazz);
        ops.addAll(fieldExpr, values,addDups);
        return dsForRW.update(query, ops);
    }

    @SuppressWarnings("unchecked")
    public <T> UpdateResults removeFromArray(final Class<?> clazz,DBObject filter,String fieldExpr, Object value)
    {
        Query<T> query = this.createQuery(clazz, filter);
        UpdateOperations<T> ops = (UpdateOperations<T>) dsForRW.createUpdateOperations(clazz);
        ops.removeAll(fieldExpr, value);
        return dsForRW.update(query, ops);
    }

    @SuppressWarnings("unchecked")
    public <T> UpdateResults removeAllFromArray(final Class<?> clazz,DBObject filter,String fieldExpr, List<?> values){
        Query<T> query = this.createQuery(clazz, filter);
        UpdateOperations<T> ops = (UpdateOperations<T>) dsForRW.createUpdateOperations(clazz);
        ops.removeAll(fieldExpr, values);
        return dsForRW.update(query, ops);
    }


    public <T>T insertOrUpdate(T entity)
    {
        if (entity == null) {
            return null;
        }
        if (entity instanceof AbstractBaseInfo) {
            AbstractBaseInfo obj = (AbstractBaseInfo) entity;
            if (obj.getId() == null) {
                obj.setId(MongodbUtil.genMongoId());
                dsForRW.insert(obj);
                return entity;
            }
        }
        dsForRW.save(entity);
        return entity;
    }
//  public <T>T insert(T entity) {
//      if (entity == null) {
//          return null;
//      }
//      Key<T> key = dsForRW.insert(entity);
//      return entity;
//  }
    public void batchInsert(List<?> objList) {
        Object[]arrays = new Object[objList.size()];
        int i=0;
        for(Object obj :objList){
            if(obj instanceof AbstractBaseInfo){
                AbstractBaseInfo entity = (AbstractBaseInfo)obj;
                if(entity.getId()==null)
                {
                    entity.setId(MongodbUtil.genMongoId());
                }
                arrays[i++]=entity;
            }else{
                arrays[i++]=obj;
            }
        }
        dsForRW.insert(arrays);
    }

    public <T> T get(final Class<?> clazz,String field,Object value)
    {
        Query<T> query = this.createQuery(clazz, new BasicDBObject(field,value));
        return query.get();
    }

    public <T> T get(final Class<?> clazz,DBObject filter)
    {
        Query<T> query = this.createQuery(clazz, filter);
        return query.get();
    }

    public <T> List<T> getList(final Class<?> clazz,String field,Object value){
        return this.getList(clazz, new BasicDBObject(field,value));
    }

    public <T> List<T> getList(final Class<?> clazz,DBObject filter)
    {
        Query<T> query = this.createQuery(clazz, filter);
        return query.asList();
    }

    public <T> List<T> getList(final Class<?> clazz,DBObject filter,String sort)
    {
        Query<T> query = this.createQuery(clazz, filter);
        if(StringUtils.isNotEmpty(sort)){
            query.order(sort);
        }
        return query.asList();
    }

    public <T> List<T> getList(final Class<?> clazz,DBObject filter,String sort,int limit)
    {
        Query<T> query = this.createQuery(clazz, filter);
        if(StringUtils.isNotEmpty(sort)){
            query.order(sort);
        }
        if(limit>0){
            query.offset(0).limit(limit);
        }
        return query.asList();
    }
//  /**
//   * 
//   * @param clazz
//   * @param filter 过滤条件
//   * @param sort 排序条件 <li>{@code order("age,-date")} (age ascending, date descending)</li>
//   * @param pageSize  每页大小
//   * @param pageIndex 第几页,从0开始
//   * @return
//   */
//  public <T> PageVO<T> getPageData(final Class<?> clazz,DBObject filter,String sort,int pageSize,int pageIndex){
//      if(pageSize<=0){
//          pageSize = 20;
//      }
//      Query<T> query = this.createQuery(clazz, filter);
//      long totalCount = query.countAll();
//      if(StringUtils.isNotEmpty(sort)){
//          query.order(sort);
//      }
//      query.offset(pageIndex * pageSize).limit(pageSize);
//      List<T> list= query.asList();
//      PageVO<T> result = new PageVO<>(list,totalCount,pageSize);
//      return result;
//  }

    public boolean exists(final Class<?> clazz,DBObject query){
        return dsForRW.getCollection(clazz).getCount(query)>0;
    }

    public <T> void remove(final Class<?> clazz,DBObject filter){
        if(filter==null){
            throw new ServiceException("删除条件为空");
        }
        Set<String>key = filter.keySet();
        if(key==null || key.isEmpty()){
            throw new ServiceException("删除条件为空");
        }
        Query<T> query = this.createQuery(clazz, filter);
        dsForRW.delete(query);
    }

    @SuppressWarnings("unchecked")
    public <T> void cleanTable(final Class<?> clazz){
        Query<T> query = (Query<T>) dsForRW.createQuery(clazz);
        dsForRW.delete(query);
    }
    /**
     * field支持多级嵌套 ,比如:order.patient.id
     */
    public List<String> stringFieldList(final Class<?> clazz,DBObject filter,String field){

        DBObject projection = new BasicDBObject();
        projection.put(field, 1);//1表示返回的数据 只包含这个字段,0表示排除

        DBCursor cursor =  dsForRW.getCollection(clazz).find(filter, projection);
        List<String> fieldValueList = new ArrayList<String>();
        while (cursor.hasNext()) {
            DBObject obj = cursor.next();
            fieldValueList.add(getFieldValue(obj,field.split("\\.")));
        }
        return fieldValueList;
    }

    private String getFieldValue(DBObject dbObj,String[]fields){
         int length = fields.length;
         if(length>1){
             Object obj = dbObj.get(fields[0]);
             if(obj instanceof DBObject){
                String[]subFields = new String[length-1];
                System.arraycopy(fields, 1, subFields, 0, length-1);
                return getFieldValue((DBObject)obj,subFields);
             }
         }else if(length==1){
             return MongodbUtil.getString(dbObj, fields[0]);
         }
         return null;
    }


    @SuppressWarnings("unchecked")
    private <T> UpdateOperations<T> createUpdateOperations(final Class<?> clazz,DBObject update){
        UpdateOperations<T> ops = (UpdateOperations<T>) dsForRW.createUpdateOperations(clazz);
        for( String field:update.keySet()){
            ops.set(field, update.get(field));
        }
        return ops;
    }

    @SuppressWarnings("unchecked")
    private <T> Query<T> createQuery(final Class<?> clazz,DBObject filter) {
        Query<T> query = (Query<T>) dsForRW.createQuery(clazz);
        if(filter!=null){
            for(String condition:filter.keySet()){
                query.filter(condition, filter.get(condition));
            }
        }
        return query;
    }


    @SuppressWarnings("unchecked")
    private <T> Query<T> createQuery(final Class<?> clazz,String id) {
        Query<T> query = (Query<T>) dsForRW.createQuery(clazz);
        query.filter(Mapper.ID_KEY,id);
        return query;
    }
    /**
     * @see org.mongodb.morphia.query.FieldEndImpl
     * 模糊查询 :左右模糊   TODO
     * 
     *   DBObject query = new BasicDBObject();
         query.put("name", like(userName));
     */
    private BasicDBObject like(String content) {
         Pattern pattern = Pattern.compile("^.*" + content + ".*$", Pattern.CASE_INSENSITIVE);
         return new BasicDBObject("$regex", pattern);
    }

    /*
     * 模糊查询: TODO
        DBObject query = new BasicDBObject();
        query.put("filename", endWith(“.pdf”));
     */
    private BasicDBObject endWith(String content) {
        Pattern pattern = Pattern.compile(content + "$", Pattern.MULTILINE);
        return new BasicDBObject("$regex", pattern);
    }

    public <T> DBCollection getCollection(Class<?> clazz) {
        return dsForRW.getCollection(clazz);
    }
    /**
     * 排除某些属性
     */
    public <T> T getInfoExcludeField(Class<?> clazz, DBObject filter, String... ignoringFields) {
        Query<T> query = this.createQuery(clazz, filter);
        if(ignoringFields!=null && ignoringFields.length>0){
            query.retrievedFields(false, ignoringFields);
        }
        return query.get();
    }

    public <T> T getInfoIncludeField(Class<?> clazz, DBObject filter,String... includeFields) {
        Query<T> query = this.createQuery(clazz, filter);
        if(includeFields!=null && includeFields.length>0){
            query.retrievedFields(true, includeFields);
        }
        return query.get();
    }

    public <T> List<T> getListExcludeField(Class<?> clazz, DBObject filter,String sort, String... ignoringFields) {
        Query<T> query = this.createQuery(clazz, filter);
        if(ignoringFields!=null && ignoringFields.length>0){
            query.retrievedFields(false, ignoringFields);
        }
        if(StringUtils.isNotEmpty(sort)){
            query.order(sort);
        }
        return query.asList();
    }

    public <T> List<T> getListIncludeField(Class<?> clazz, DBObject filter,String sort, String... includeFields) {
        Query<T> query = this.createQuery(clazz, filter);
        if(StringUtils.isNotEmpty(sort)){
            query.order(sort);
        }
        if(includeFields!=null && includeFields.length>0){
            query.retrievedFields(true, includeFields);
        }
        return query.asList();
    }

    /**
     * {
        key: { userId: 1 },
        cond: { appId:  "10001" },
        reduce: function( curr, result ) {
                    result.total += curr.money;
                },
        initial: { total : 0 }
       }
       ==
       select userId,sum(money) as total from tablename where appId="10001"
     * <p>描述:</p>
     * @param clazz
     * @param key
     * @param cond
     * @param initial
     * @param reduce
     */
    @SuppressWarnings("unchecked")
    public List<DBObject> group(final Class<?> clazz,final DBObject key, final DBObject cond, final DBObject initial, final String reduce){
        return (List<DBObject>) dsForRW.getCollection(clazz).group(key, cond, initial, reduce);
    }

    /**
     * select userId,sum(money) as total from tablename where appId="10001"
     * 条件(pipeline0)   :{$match:{"appId":"10001"}}
     * 分组统计(pipeline1):{$group:{"_id":"$userId","total":{$sum:"$money"}}}
     *  group支持操作:$sum,$avg,$first,$last,$max,$min,$push,$addToSet,$stdDevPop,$stdDevSamp
     * <p>描述:</p>
     * @param clazz
     * @param pipeline
     * @return
     */
//  private Iterable<DBObject> aggregate(final Class<?> clazz,final List<? extends DBObject> pipeline){
//      AggregationOutput out = dsForRW.getCollection(clazz).aggregate(pipeline);
//      if(out!=null){
//          return out.results();
//      }
        dsForRW.getCollection(clazz).aggregate(pipeline, options)
//      return null;
//  }

    @SuppressWarnings("unchecked")
    public List<Object> distinct(final Class<?> clazz,final String fieldName, final DBObject query){
        return dsForRW.getCollection(clazz).distinct(fieldName, query);
    }

    public long count(final Class<?> clazz,final DBObject query){
        return dsForRW.getCollection(clazz).count(query);
    }
    //***************************************************************************//
    /**
     * 
     * @param clazz
     * @param requestList
     * @param updateOne true表示只更新匹配的一条数据
     * @param createIfMissing 如果不存在则插入新的文档[查询部分和更新部分的结合 ]
     */
    public void batchUpdate(final Class<?> clazz,List<BatchUpdateRequest> requestList,boolean updateOne,boolean createIfMissing) {
        if(requestList==null || requestList.size()<=0){
            return;
        }
        int PAGE_SIZE =1000;
        int totalSize = requestList.size();
        if(totalSize<=PAGE_SIZE){
            this.batchUpdateByPage(clazz, requestList,updateOne,createIfMissing);
        }else{
            int lastPageCount = totalSize % PAGE_SIZE;
            int count = totalSize / PAGE_SIZE;
            if(lastPageCount>0) {
                count++;
            }
            List<BatchUpdateRequest>subList = null;
            int toIndex = 0;
            for(int i=0;i<count;i++)
            {
                toIndex =(i+1) * PAGE_SIZE; 
                if(toIndex > totalSize){
                    toIndex = totalSize;
                }
                subList = requestList.subList(i * PAGE_SIZE, toIndex);
                this.batchUpdateByPage(clazz, subList,updateOne,createIfMissing);
            }
        }

    }

    private void batchUpdateByPage(final Class<?> clazz,List<BatchUpdateRequest> requestList,boolean updateOne,boolean createIfMissing) {
        BulkWriteOperation bulk = dsForRW.getCollection(clazz).initializeOrderedBulkOperation();
        for(BatchUpdateRequest request : requestList){
            if(request.getFilter()==null && request.getPk()!=null){
                request.setFilter(new BasicDBObject("_id", request.getPk()));
            }
            DBObject update = new BasicDBObject();
            if(request.getUpdate()!=null){
                update.put("$set", request.getUpdate());
            }
            if(request.getInc()!=null){
                update.put("$inc", request.getInc());
            }
            if(update.keySet()==null || update.keySet().isEmpty()){
                continue;
            }
            if(createIfMissing){
                if(updateOne){
                    bulk.find(request.getFilter()).upsert().updateOne(update);
                }else{
                    bulk.find(request.getFilter()).upsert().update(update);
                }
            }else{
                if(updateOne){
                    bulk.find(request.getFilter()).updateOne(update);
                }else{
                    bulk.find(request.getFilter()).update(update);
                }
            }
        }
        bulk.execute();
    }
    /**
     * 暂不支持嵌套对象
     * @param clazz
     * @param objList
     */
    public void batchInsertOrUpdate(final Class<?> clazz,List<? extends AbstractBaseInfo> objList) {
        if(objList==null || objList.size()<=0){
            return;
        }
        BulkWriteOperation bulk = dsForRW.getCollection(clazz).initializeOrderedBulkOperation();

        DBObject document;
        for(AbstractBaseInfo obj :objList){
            if(obj.getId()==null){
                obj.setId(MongodbUtil.genMongoId());
            }
            try {
                document = bean2DBObject(obj);
                bulk.find(new BasicDBObject("_id", obj.getId())).upsert().updateOne(new BasicDBObject("$set",document));
            } catch (IllegalArgumentException | IllegalAccessException e) {
                logger.error(e.getMessage());
            }
        }
        bulk.execute();
    }

    /**
     * 暂不支持嵌套对象
     * @param clazz
     * @param objList
     */
    public void batchUpdate(final Class<?> clazz,List<? extends AbstractBaseInfo> objList) {
        BulkWriteOperation bulk = dsForRW.getCollection(clazz).initializeUnorderedBulkOperation();
        for(AbstractBaseInfo obj :objList){
            if(obj.getId()==null){
                continue;
            }
            DBObject document;
            try {
                document = bean2DBObject(obj);
                bulk.find(new BasicDBObject("_id", obj.getId())).updateOne(new BasicDBObject("$set",document));
            } catch (IllegalArgumentException | IllegalAccessException e) {
                logger.error(e.getMessage());
            }
        }
        bulk.execute();
    }
//  public MongoClient mongoClient(){
//      return dsForRW.getMongo();
//  }

    private static <T> DBObject bean2DBObject(T bean) throws IllegalArgumentException, IllegalAccessException {
        if (bean == null) {
            return null;
        }
        DBObject dbObject = new BasicDBObject();
        // 获取对象对应类中的所有属性域
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 获取属性名
            String varName = field.getName();
            // 修改访问控制权限
            boolean accessFlag = field.isAccessible();
            if (!accessFlag) {
                field.setAccessible(true);
            }
            Object param = field.get(bean);
            if (param == null) {
                continue;
            } 
            dbObject.put(varName, param);
            // 恢复访问控制权限
            field.setAccessible(accessFlag);
        }
        return dbObject;
    }
}

5.其他辅助类

package com.h.mongo;

import org.mongodb.morphia.annotations.Id;

/**
 * mongo实体基类
 * @author Administrator
 */
public abstract class AbstractBaseInfo {

    @Id
    private String id;

    private String clientAppId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AbstractBaseInfo other = (AbstractBaseInfo) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    public String getClientAppId() {
        return clientAppId;
    }

    public void setClientAppId(String clientAppId) {
        this.clientAppId = clientAppId;
    }
}
package com.h.mongo;

import com.mongodb.DBObject;

public class BatchUpdateRequest {

    private Object pk;

    private DBObject filter;

    private DBObject update;

    private DBObject inc;

    public DBObject getFilter() {
        return filter;
    }

    public void setFilter(DBObject filter) {
        this.filter = filter;
    }

    public DBObject getUpdate() {
        return update;
    }

    public void setUpdate(DBObject update) {
        this.update = update;
    }

    public Object getPk() {
        return pk;
    }

    public void setPk(Object pk) {
        this.pk = pk;
    }

    public DBObject getInc() {
        return inc;
    }

    public void setInc(DBObject inc) {
        this.inc = inc;
    }
}
package com.h.mongo;

import org.mongodb.morphia.converters.SimpleValueConverter;
import org.mongodb.morphia.converters.TypeConverter;
import org.mongodb.morphia.mapping.MappedField;
import org.mongodb.morphia.mapping.MappingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;

public class BigDecimalConverter extends TypeConverter implements SimpleValueConverter {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    public BigDecimalConverter() {
        super(BigDecimal.class);
    }
    @Override
    protected boolean isSupported(Class<?> c, MappedField optionalExtraInfo) {
        return BigDecimal.class.isAssignableFrom(c);
    }

    @Override
    public Object encode(Object value, MappedField optionalExtraInfo) {
        if (value == null) return null;  

        return value.toString();
    }

    @Override
    public Object decode(Class targetClass, Object fromDBObject, MappedField optionalExtraInfo) throws MappingException {
        if (fromDBObject == null) return null;  
        try{
            if (fromDBObject instanceof String) {
                return new BigDecimal((String)fromDBObject);
            }else if (fromDBObject instanceof Number) {
                return new BigDecimal(((Number)fromDBObject).doubleValue());
            }else{
                logger.warn(fromDBObject.toString());
            }
        }catch(NumberFormatException e){
            logger.warn(fromDBObject.toString());
        }
        return null;
    }


}
package com.h.mongo;

import org.mongodb.morphia.annotations.Entity;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassUtil {
    public static void main(String[] args) {
        Set<Class<?>> classSet = getAllClassByAnnotation("com.h");
        for (Class cls:classSet){
            System.out.println(cls);
        }
    }
    /**
     * 取得某个包下所有实现这个接口的类
     */
    public static Set<Class<?>> getAllClassByAnnotation(String packageName) {
        List<Class<?>> classList =ClassUtil.getClasses(packageName) ;
        Set<Class<?>> returnClassList = new HashSet<>();
        for(Class<?> clazz:classList){
            Entity entity = clazz.getAnnotation(Entity.class);
            if(entity!=null){
                returnClassList.add(clazz);
            }else{
//              System.out.println();
            }
        }
        return returnClassList;
    }
    /**
     * 取得某个接口下所有实现这个接口的类
     * */
    @SuppressWarnings("rawtypes")
    public static List<Class> getAllClassByInterface(Class<?> c) {
        List<Class> returnClassList = null;

        if (c.isInterface()) {
            // 获取当前的包名
            String packageName = c.getPackage().getName();
            // 获取当前包下以及子包下所以的类
            List<Class<?>> allClass = getClasses(packageName);
            if (allClass != null) {
                returnClassList = new ArrayList<Class>();
                for (Class<?>classes : allClass) {
                    // 判断是否是同一个接口
                    if (c.isAssignableFrom(classes)) {
                        // 本身不加入进去
                        if (!c.equals(classes)) {
                            returnClassList.add(classes);
                        }
                    }
                }
            }
        }

        return returnClassList;
    }

    /*
     * 取得某一类所在包的所有类名 不含迭代
     */
    public static String[] getPackageAllClassName(String classLocation,
            String packageName) {
        // 将packageName分解
        String[] packagePathSplit = packageName.split("[.]");
        String realClassLocation = classLocation;
        int packageLength = packagePathSplit.length;
        for (int i = 0; i < packageLength; i++) {
            realClassLocation = realClassLocation + File.separator + packagePathSplit[i];
        }
        File packeageDir = new File(realClassLocation);
        if (packeageDir.isDirectory()) {
            String[] allClassName = packeageDir.list();
            return allClassName;
        }
        return null;
    }

    /**
     * 从包package中获取所有的Class
     * 
     * @param pack
     * @return
     */
    public static List<Class<?>> getClasses(String packageName) {

        // 第一个class类的集合
        List<Class<?>> classes = new ArrayList<Class<?>>();
        // 是否循环迭代
        boolean recursive = true;
        // 获取包的名字 并进行替换
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration<URL> dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()) {
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    findAndAddClassesInPackageByFile(packageName, filePath,recursive, classes);
                } else if ("jar".equals(protocol)) {
                    // 如果是jar包文件
                    // 定义一个JarFile
                    JarFile jar;
                    try {
                        // 获取jar
                        jar = ((JarURLConnection) url.openConnection()).getJarFile();
                        // 从此jar包 得到一个枚举类
                        Enumeration<JarEntry> entries = jar.entries();
                        // 同样的进行循环迭代
                        while (entries.hasMoreElements()) {
                            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
                            JarEntry entry = entries.nextElement();
                            String name = entry.getName();
                            // 如果是以/开头的
                            if (name.charAt(0) == '/') {
                                // 获取后面的字符串
                                name = name.substring(1);
                            }
                            // 如果前半部分和定义的包名相同
                            if (name.startsWith(packageDirName)) {
                                int idx = name.lastIndexOf('/');
                                // 如果以"/"结尾 是一个包
                                if (idx != -1) {
                                    // 获取包名 把"/"替换成"."
                                    packageName = name.substring(0, idx).replace('/', '.');
                                }
                                // 如果可以迭代下去 并且是一个包
                                if ((idx != -1) || recursive) {
                                    // 如果是一个.class文件 而且不是目录
                                    if (name.endsWith(".class") && !entry.isDirectory()) {
                                        // 去掉后面的".class" 获取真正的类名
                                        String className = name.substring(packageName.length() + 1,name.length() - 6);
                                        try {
                                            // 添加到classes
                                            classes.add(Class.forName(packageName + '.'+ className));
                                        } catch (ClassNotFoundException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return classes;
    }

    /**
     * 以文件的形式来获取包下的所有Class
     * 
     * @param packageName
     * @param packagePath
     * @param recursive
     * @param classes
     */
    public static void findAndAddClassesInPackageByFile(String packageName,
            String packagePath, final boolean recursive, List<Class<?>> classes) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            public boolean accept(File file) {
                return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "." + file.getName(),file.getAbsolutePath(), recursive, classes);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0,file.getName().length() - 6);
                try {
                    // 添加到集合中去
                    classes.add(Class.forName(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.h.mongo;

import com.mongodb.DBObject;
import org.bson.types.ObjectId;

public class MongodbUtil {
    public static String getString(DBObject obj, String key) {
        Object val = obj.get(key);
        return val == null ? "" : val.toString();
    }

    public static Integer getInteger(DBObject obj, String key) {
        Object val = obj.get(key);
        if (val != null) {
            if (val instanceof Number) {
                return ((Number) val).intValue();
            }
            return Integer.parseInt(val.toString());
        }
        return null;
    }

    public static int getIntValue(DBObject obj, String key) {
        Integer v = MongodbUtil.getInteger(obj, key);
        return v==null?0:v.intValue();
    }
    public static Long getLong(DBObject obj, String key) {
        Object val = obj.get(key);
        if (val != null) {
            return Long.parseLong(val.toString());
        }
        return null;
    }
    public static long getLongValue(DBObject obj, String key) {
        Long v = MongodbUtil.getLong(obj, key);
        return v==null?0:v.longValue();
    }
    public static Double getDouble(DBObject obj, String key) {
        Object val = obj.get(key);
        return val == null ? null : (Double) val;
    }

    public static Boolean getBoolean(DBObject obj, String key) {
        Object val = obj.get(key);
        return val == null ? null : (Boolean) val;
    }

    public static String genMongoId() {
        return ObjectId.get().toString();
    }

}
package com.h.mongo;

public class ServiceException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    private Integer resultCode;

    public ServiceException(Integer resultCode, String message) {
        super(message);

        this.resultCode = resultCode;
    }

    public ServiceException(String message) {
        super(message);
    }


    public Integer getResultCode() {
        return resultCode;
    }

}
package com.h.mongo;

import java.text.NumberFormat;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wanghong
 * @desc
 * @date: 2017/12/5  14:18
 * @Copyright (c) 2017, DaChen All Rights Reserved.
 */
public final class StringUtils extends org.apache.commons.lang3.StringUtils {
    public static final String CRLF = "\r\n";
    public static final String BASE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    public static final String BASE_2 = "abcdefghijklmnopqrstuvwxyz0123456789";
    public static final String BASE_3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private static final char[] charArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};

    public StringUtils() {
    }

    public static String StringFilter(String str) {
        if (str == null) {
            return str;
        } else {
            Pattern p = Pattern.compile("[\u0001\u0002\u0003\u0004\u0006\u0007\u000b\u001c\u001d\u001e\u001f]");
            Matcher m = p.matcher(str);
            return m.find() ? m.replaceAll(" ").trim() : str;
        }
    }

    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    public static boolean isNumber(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }

    public static String IdToUpperCase(String s) {
        if (s == null) {
            s = "";
        }

        s = s.trim().toUpperCase();
        s = s.replaceAll(" ", "_");
        s = s.replaceAll("_+", "_");
        return s;
    }

    public static void append(StringBuilder buf, byte b, int base) {
        int bi = 255 & b;
        int c = 48 + bi / base % base;
        if (c > 57) {
            c = 97 + (c - 48 - 10);
        }

        buf.append((char)c);
        c = 48 + bi % base;
        if (c > 57) {
            c = 97 + (c - 48 - 10);
        }

        buf.append((char)c);
    }

    public static String getRandomString(int length) {
        return randomString(length, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    }

    private static String randomString(int length, String base) {
        Random random = new Random();
        StringBuffer sb = new StringBuffer();

        for(int i = 0; i < length; ++i) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }

        return sb.toString();
    }

    public static String getRandomString2(int length) {
        return randomString(length, "abcdefghijklmnopqrstuvwxyz0123456789");
    }

    public static String randomId() {
        return randomString(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    }

    public static String randomUUID() {
        UUID uuid = UUID.randomUUID();
        String uuidStr = uuid.toString().replace("-", "");
        return uuidStr;
    }

    public static boolean startsWith(CharSequence str, CharSequence prefix) {
        return org.apache.commons.lang3.StringUtils.startsWith(str, prefix);
    }

    public static boolean endsWith(CharSequence str, CharSequence suffix) {
        return org.apache.commons.lang3.StringUtils.endsWith(str, suffix);
    }

    public static String[] split(String str, String separatorChars) {
        return org.apache.commons.lang3.StringUtils.split(str, separatorChars);
    }

    public static String[] split(String str, String separatorChars, int max) {
        return org.apache.commons.lang3.StringUtils.split(str, separatorChars, max);
    }

    public static boolean equals(CharSequence cs1, CharSequence cs2) {
        return org.apache.commons.lang3.StringUtils.equals(cs1, cs2);
    }

    public static String join(Object[] array, String separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String getExt(String filename) {
        return filename.substring(filename.lastIndexOf(46));
    }

    public static boolean isEmpty(String s) {
        return isNullOrEmpty(s);
    }

    public static boolean isNullOrEmpty(String s) {
        return null == s || 0 == s.trim().length();
    }

    public static String randomCode() {
        return "" + ((new Random()).nextInt(899999) + 100000);
    }

    public static String random4Code() {
        return "" + ((new Random()).nextInt(8999) + 1000);
    }

    public static String randomPassword() {
        return randomString(6);
    }

    public static String randomString(int length) {
        StringBuffer sb = new StringBuffer();

        for(int i = 0; i < length; ++i) {
            int index = (new Random()).nextInt(36);
            sb.append(charArray[index]);
        }

        return sb.toString();
    }

    public static String getFormatName(String fileName) {
        int index = fileName.lastIndexOf(46);
        return -1 == index ? "jpg" : fileName.substring(index + 1);
    }

    public static String format(long number, int length) {
        NumberFormat nf = NumberFormat.getInstance();
        nf.setMaximumIntegerDigits(length);
        nf.setMinimumIntegerDigits(length);
        nf.setGroupingUsed(false);
        return nf.format(number);
    }

    public static String atKey(String telephone, Integer userType) {
        return String.format("uk_%1$s_%2$d", telephone, userType);
    }

    public static String atValue(String orderRecharegeNo, String refundRrice, String refundReason) {
        return String.format("%1$s^%2$s^%3$s", orderRecharegeNo, refundRrice, refundReason);
    }

    public static boolean isMobiPhoneNum(String telNum) {
        String regex = "^((13[0-9])|(15[0-9])|(18[0-9]))\\d{8}$";
        Pattern p = Pattern.compile(regex, 2);
        Matcher m = p.matcher(telNum);
        return m.matches();
    }
}

package com.h.util;

import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;

public class BeanUtil {

     public static <T> T copy(Object poObj,final Class <T>voClass)
     {
         T voObj =null;
         try {
             voObj = voClass.newInstance();
             BeanUtils.copyProperties(poObj, voObj);
             return voObj;
         } catch (InstantiationException | IllegalAccessException e) {
             e.printStackTrace();
         }
         return null;
     }
     public static <T> List <T> copyList(List <? extends Object> poList ,final Class <T>voClass){

        List<T> voList=new ArrayList<T>();

        T voObj =null;
        for(Object poObj:poList){
            try {
                voObj = voClass.newInstance();
                BeanUtils.copyProperties(poObj, voObj);
                voList.add(voObj);
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
//            System.out.println(voObj);
        }
        return voList;
    }
}

6.使用示例

 package com.dachen.microschool.model.po;

import com.dachen.support.mongo.base.AbstractBaseInfo;
import io.swagger.annotations.ApiModelProperty;
import org.mongodb.morphia.annotations.Entity;

import java.util.List;

/**
 * @author wanghong
 * @desc
 * @date: 2017/11/14  11:33
 * @Copyright (c) 2017, DaChen All Rights Reserved.
 * 课程表
 */
@Entity(value = "t_course",noClassnameStored = true)
public class Course extends AbstractBaseInfo {

    @ApiModelProperty(value = "讲堂ID")
    private String classId;

    @ApiModelProperty(value = "课程所属人[冗余]")
    private String ownerId;

    @ApiModelProperty(value = "课程主题")
    private String theme;

    @ApiModelProperty(value = "修改时间")
    private Long updateTime;

    @ApiModelProperty(value = "创建时间")
    private Long createTime;

    @ApiModelProperty(value = "课程开讲时间")
    private Long beginTime;

    @ApiModelProperty(value = "课程形式 0-幻灯片形式 1-聊天形式")
    private int form;

    @ApiModelProperty(value = "课程类型 0-公开课 1-收费课")
    private int type;

    @ApiModelProperty(value = "封面题图")
    private String coverImgUrl;

    @ApiModelProperty(value = "课程简介")
    private String introduce;

    @ApiModelProperty(value = "课程摘要")
    private String digest;

    @ApiModelProperty(value = "课程创建人")
    private String creator;

    @ApiModelProperty(value = "课程标签集合")
    private List<String> labels;

    @ApiModelProperty(value = "课程状态 0-草稿 1-发布 9-结束")
    private int status;

    @ApiModelProperty(value = "课程发布范围类型 0-全员公开 1-指定圈子范围 2-指定科室(课程所属用户所在科室)")
    private Integer publishType;

    get/set()....
}
package com.dachen.microschool.model.request;

import io.swagger.annotations.ApiModelProperty;

import java.util.List;

/**
 * @author wanghong
 * @desc
 * @date: 2017/12/1  15:09
 * @Copyright (c) 2017, DaChen All Rights Reserved.
 */
public class CourseRequest {

    @ApiModelProperty(value = "讲堂ID")
    private String classId;

    @ApiModelProperty(value = "课程所属人[冗余]")
    private String ownerId;

    @ApiModelProperty(value = "课程主题")
    private String theme;

    @ApiModelProperty(value = "课程开讲时间")
    private Long beginTime;

    @ApiModelProperty(value = "课程形式 0-幻灯片形式 1-聊天形式")
    private int form;

    @ApiModelProperty(value = "课程类型 0-公开课 1-收费课")
    private int type;

    @ApiModelProperty(value = "封面题图")
    private String coverImgUrl;

    @ApiModelProperty(value = "课程简介")
    private String introduce;

    @ApiModelProperty(value = "课程摘要")
    private String digest;

    @ApiModelProperty(value = "课程创建人")
    private String creator;

    @ApiModelProperty(value = "课程标签集合")
    private List<String> labelNameList;

    @ApiModelProperty(value = "课程发布范围类型 0-全员公开 1-指定圈子范围 2-指定科室(课程所属用户所在科室)")
    private Integer publishType;

    get/set()
}
//客户端调用
@ApiOperation(value="新建课程", httpMethod="POST", response=String.class, notes = "成功返回  \"data\": \"课程id\"")
    @RequestMapping(value="/createCourse", method= RequestMethod.POST)
    public Result createCourse(@RequestBody CourseRequest courseRequest){
        return  Result.build(courseService.createCourse(courseRequest));
    }

 //新增
  Course course = BeanUtil.copy(courseRequest, Course.class);
  course.setCreateTime(System.currentTimeMillis()); 
  mongoCommonDAO.insertOrUpdate(course);

//批量更新多条记录
 /**
     * 添加课程课件/素材
     * 每次添加前先逻辑删除原先的该课程下的课件,再保存
     * @param coursewareList
     */
    public void addCourseWare(List<CoursewareRequest> coursewareList){
        if (CollectionUtils.isNotEmpty(coursewareList)){
            String courseId =coursewareList.get(0).getCourseId();

            DBObject query = new BasicDBObject();
            query.put("courseId",courseId);
            query.put("deleted",0);
            List<Courseware> list = mongoCommonDAO.getList(Courseware.class,query);
            if (CollectionUtils.isNotEmpty(list)){
                //批量更新删除状态
                List<BatchUpdateRequest>updateList = new ArrayList<>(list.size());
                BatchUpdateRequest req = null;
                for (Courseware cw:list){
                    req = new BatchUpdateRequest();
                    req.setPk(cw.getId());
                    DBObject update = new BasicDBObject("deleted",1);
                    req.setUpdate(update);
                    updateList.add(req);
                }
                mongoCommonDAO.batchUpdate(Courseware.class, updateList,true,false);
            }

                int size = coursewareList.size();
                list = new ArrayList<>(size);
                for (int i=0;i<size;i++){
                    CoursewareRequest request = coursewareList.get(i);
                    Courseware courseware = new Courseware();
                    courseware.setCourseId(courseId);
                    courseware.setPageNumber(i);
                    courseware.setDeleted(0);
                    courseware.setType(request.getType());
                    courseware.setName(request.getName());
                    courseware.setUrl(request.getUrl());

                    list.add(courseware);
                }
                mongoCommonDAO.batchInsert(list);
        }
    }

//聚合查询
/**
     * 批量获取课程列表
     * @param courseIdList
     * @return
     */
    public List<CourseVO> getCourseList(List<String> courseIdList){
        Map<String,Object> map = new HashMap<>();
        map.put("id in", courseIdList);
        DBObject query = new BasicDBObject(map);
        //或者下面的写法
        //DBObject query = new BasicDBObject();
       // query.put("_id",new BasicDBObject("$in",courseIdList));
        List<Course> courseList = mongoCommonDAO.getList(Course.class,query);
        return wrapCourse(courseList);
    }
 类似资料: