Mongodb初探(一):实现对自定义Bean对象的CURD

1. 有一个自定义的Bean对象类,代码如下:

public class TestBean extends Document{
    /**
     * 序列化部分不管
     */
    private static final long serialVersionUID = 3610201746888594945L;

    public TestBean() {
        super();
    }
    /**
    *构造函数传入3个字段值,添加到Map中
    */
    public TestBean(String name, Integer sex, Date date) {
        super();
        this.append("name", name).append("sex", sex).append("date", date);
    }

    /**
    *该方法用于collection的update
    */
    public void setUpdate(TestBean bean){
        this.append("$set", bean);
    }
    //以下都是获取和设置字段值
    public ObjectId getId() {
        return this.getObjectId("_id");
    }
    public void setId(ObjectId id){
        this.append("_id", id);
    }
    public String getName() {
        return this.getString("name");
    }

    public void setName(String name) {
        this.append("name", name);
    }

    public Integer getSex() {
        return this.getInteger("sex");
    }

    public void setSex(Integer sex) {
        this.append("sex", sex);
    }

    public Date getDate() {
        return this.getDate("date");
    }

    public void setDate(Date date) {
        this.append("date", date);
    }

    @Override
    public String toString() {
        return "TestBean [id=" + getId().toString() + ", name=" + getName() + ", sex=" + getSex() + ", date=" + getDate() + "]";
    }

    public <TDocument> BsonDocument toBsonDocument(Class<TDocument> documentClass, CodecRegistry codecRegistry) {
        // TODO Auto-generated method stub
        return new BsonDocumentWrapper<TestBean>(this, codecRegistry.get(TestBean.class));
    }
}

Document是Map结构的,所以字段全部存储在Map中;
最后一个方法覆写了Bson接口的定义,该方法的作用是将TestBean对象转换为BsonDocument,用到了CodecRegistry的encode方法。


2. 对应该Bean对象有一个实现了CollectibleCodec接口类的转换类:

public class TestBeanCodec implements CollectibleCodec<TestBean> {
    private static final Logger LOG = LoggerFactory.getLogger(TestBeanCodec.class);
    private static final String ID_FIELD_NAME = "_id";
    private static final CodecRegistry DEFAULT_REGISTRY = fromProviders(asList(new ValueCodecProvider(),
            new BsonValueCodecProvider(),
            new DocumentCodecProvider()));
    private static final BsonTypeClassMap DEFAULT_BSON_TYPE_CLASS_MAP = new BsonTypeClassMap();

    private final CodecRegistry registry;
    private final BsonTypeClassMap bsonTypeClassMap;
    private final IdGenerator idGenerator;
    private final Transformer valueTransformer;

    public TestBeanCodec() {
        this(DEFAULT_REGISTRY, DEFAULT_BSON_TYPE_CLASS_MAP);
    }

    public TestBeanCodec(final CodecRegistry registry, final BsonTypeClassMap bsonTypeClassMap) {
        this(registry, bsonTypeClassMap, null);
    }

    public TestBeanCodec(final CodecRegistry registry, final BsonTypeClassMap bsonTypeClassMap, final Transformer valueTransformer) {
        this.registry = Assertions.notNull("registry", registry);
        this.bsonTypeClassMap = Assertions.notNull("bsonTypeClassMap", bsonTypeClassMap);
        this.idGenerator = Assertions.notNull("idGenerator", new ObjectIdGenerator());
        this.valueTransformer = valueTransformer != null ? valueTransformer : new Transformer() {
            @Override
            public Object transform(final Object value) {
                return value;
            }
        };
    }
    @Override
    public boolean documentHasId(final TestBean document) {
        return document.containsKey(ID_FIELD_NAME);
    }

    @Override
    public BsonValue getDocumentId(final TestBean document) {
        if (!documentHasId(document)) {
            throw new IllegalStateException("The document does not contain an _id");
        }

        Object id = document.get(ID_FIELD_NAME);
        if (id instanceof BsonValue) {
            return (BsonValue) id;
        }

        BsonDocument idHoldingDocument = new BsonDocument();
        BsonWriter writer = new BsonDocumentWriter(idHoldingDocument);
        writer.writeStartDocument();
        writer.writeName(ID_FIELD_NAME);
        writeValue(writer, EncoderContext.builder().build(), id);
        writer.writeEndDocument();
        return idHoldingDocument.get(ID_FIELD_NAME);
    }

    @Override
    public TestBean generateIdIfAbsentFromDocument(final TestBean document) {
        if (!documentHasId(document)) {
            document.put(ID_FIELD_NAME, idGenerator.generate());
        }
        return document;
    }

    @Override
    public void encode(final BsonWriter writer, final TestBean document, final EncoderContext encoderContext) {
        LOG.info("encoderContext.isEncodingCollectibleDocument() : "+ encoderContext.isEncodingCollectibleDocument());
        writeMap(writer, document, encoderContext);
    }

    @Override
    public TestBean decode(final BsonReader reader, final DecoderContext decoderContext) {

        TestBean document = new TestBean();

        reader.readStartDocument();
        while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
            String fieldName = reader.readName();
            document.put(fieldName, readValue(reader, decoderContext));
        }

        reader.readEndDocument();

        return document;
    }

    @Override
    public Class<TestBean> getEncoderClass() {
        return TestBean.class;
    }

    private void beforeFields(final BsonWriter bsonWriter, final EncoderContext encoderContext, final Map<String, Object> document) {
        if (encoderContext.isEncodingCollectibleDocument() && document.containsKey(ID_FIELD_NAME)) {
            bsonWriter.writeName(ID_FIELD_NAME);
            writeValue(bsonWriter, encoderContext, document.get(ID_FIELD_NAME));
        }
    }

    private boolean skipField(final EncoderContext encoderContext, final String key) {
        return encoderContext.isEncodingCollectibleDocument() && key.equals(ID_FIELD_NAME);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void writeValue(final BsonWriter writer, final EncoderContext encoderContext, final Object value) {
        if (value == null) {
            writer.writeNull();
        } else if (Iterable.class.isAssignableFrom(value.getClass())) {
            writeIterable(writer, (Iterable<Object>) value, encoderContext.getChildContext());
        } else if (Map.class.isAssignableFrom(value.getClass())) {
            writeMap(writer, (Map<String, Object>) value, encoderContext.getChildContext());
        } else {
            Codec codec = registry.get(value.getClass());
            encoderContext.encodeWithChildContext(codec, writer, value);
        }
    }

    private void writeMap(final BsonWriter writer, final Map<String, Object> map, final EncoderContext encoderContext) {
        writer.writeStartDocument();

        beforeFields(writer, encoderContext, map);

        for (final Map.Entry<String, Object> entry : map.entrySet()) {
            if (skipField(encoderContext, entry.getKey())) {
                continue;
            }
            writer.writeName(entry.getKey());
            writeValue(writer, encoderContext, entry.getValue());
        }
        writer.writeEndDocument();
    }

    private void writeIterable(final BsonWriter writer, final Iterable<Object> list, final EncoderContext encoderContext) {
        writer.writeStartArray();
        for (final Object value : list) {
            writeValue(writer, encoderContext, value);
        }
        writer.writeEndArray();
    }

    private Object readValue(final BsonReader reader, final DecoderContext decoderContext) {
        BsonType bsonType = reader.getCurrentBsonType();
        if (bsonType == BsonType.NULL) {
            reader.readNull();
            return null;
        } else if (bsonType == BsonType.ARRAY) {
           return readList(reader, decoderContext);
        } else if (bsonType == BsonType.BINARY) {
            byte bsonSubType = reader.peekBinarySubType();
            if (bsonSubType == BsonBinarySubType.UUID_STANDARD.getValue() || bsonSubType == BsonBinarySubType.UUID_LEGACY.getValue()) {
                return registry.get(UUID.class).decode(reader, decoderContext);
            }
        }
        return valueTransformer.transform(registry.get(bsonTypeClassMap.get(bsonType)).decode(reader, decoderContext));
    }

    private List<Object> readList(final BsonReader reader, final DecoderContext decoderContext) {
        reader.readStartArray();
        List<Object> list = new ArrayList<Object>();
        while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
            list.add(readValue(reader, decoderContext));
        }
        reader.readEndArray();
        return list;
    }

}

该部分内容全部来自类DocumentCodec,将其中的Document类替换为自己的定义的Bean对象类;
该类主要实现了Codec接口定义的3个方法,分别是encode将TestBean转换为Bson,getEncoderClass获取到对象的Class类,decode将Bson转换为TestBean。
注意导入包时,要导入静态的aslist方法和fromProviders方法
import static java.util.Arrays.asList;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;


3. CURD测试:

public class DriverTest {

    static{
    PropertyConfigurator.configure(System.getProperty("user.dir")+ "/log4j.Properties");
    }

    private static final Logger LOG = LoggerFactory.getLogger(DriverTest.class);

    public void startTest(){
        CodecRegistry registry  = CodecRegistries.fromCodecs(new TestBeanCodec());
        MongoClient client = new MongoClient();
        MongoDatabase database = client.getDatabase("testDb");
        MongoCollection<TestBean> collection = database.withCodecRegistry(registry).getCollection("TestBeanCollec", TestBean.class);
        TestBean bean = new TestBean("www",01,new Date());
        //增
        collection.insertOne(bean);
        //查
        Block<TestBean> block = new Block<TestBean>() {

            public void apply(TestBean t) {
                // TODO Auto-generated method stub
                LOG.info(t.toString());
            }
        };
        collection.find(bean).forEach(block);
        //改
        bean = new TestBean();
        bean.setName("www");
        TestBean newBean = new TestBean("yyy", 02, new Date());
        TestBean update = new TestBean();
        update.setUpdate(newBean);
        collection.updateMany(bean, update);
        //删
        bean = new TestBean();
//      bean.setId(new ObjectId("5630e02c00e65f13894071f6"));
        bean.setName("www");
        collection.deleteMany(bean);

        client.close();
    }

    public static void main(String[] args) {
        DriverTest test = new DriverTest();
        test.startTest();
    }
}

总结:这样的Bean对象还是有点繁琐,而且每一个实现CollectibleCodec接口的代码都重复而且很多,考虑到之前直接实现Codec接口的方式,可以对Bean对象创建的字段进行插入、查找、删除,但是进行更新时因为第二个参数Bson filter要传入一个类似——”$set”这样的表示如何更新数据的修饰符,而在Codec接口的实现中并不知道如何处理,这是一个以后可以继续修改完善的方向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值