开发者社区> 问答> 正文

MongoDB 不序列化Java属性类问题

MongoDB 不序列化Java属性类问题

展开
收起
李博 bluemind 2019-04-08 11:39:05 2258 0
1 条回答
写回答
取消 提交回答
  • 云栖社区Java、Redis、MongoDB运营小编,有意合作请联系钉钉:15810436147

    Spring boot 是 2.1.0.RELEASE



    org.springframework.boot
    spring-boot-starter-data-mongodb


    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
    <scope>provided</scope>


    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>


    对象不完全序列化
    最近在项目中存储数据到 MongoDB 中时,发现对象中属性是对象时不能被自动序列化到 MongoDB 中。数据其实就是快递公司的物流轨迹信息。

    数据表现
    db.kuaidibird.find()
    { "_id" : ObjectId("5caa1336f2cc84bbd083e942"), "callback" : "1-2-3", "callback_time" : NumberLong(1554650510), "ebussinessid" : "", "iskuaidaoyun" : 1, "logisticcode" : "V0123", "ordercode" : "1-2-3", "reason" : "", "shippercode" : "jd", "state" : "已签收", "subscribe_time" : 0, "success" : false, "traces" : [ { "acceptStation" : "北京亦庄发出", "acceptTime" : "2019-04-01" }, { "acceptStation" : "北京亦庄出库", "acceptTime" : "2019-04-02" }, { "acceptStation" : "北京昌平收货", "acceptTime" : "2019-04-03" }, { "acceptStation" : "北京昌平签收", "acceptTime" : "2019-04-04" } ] }
    可以看到对于键 traces 存储的对象未正确序列化,期望是非驼峰,全部小写。

    Java Bean 对象
    主要对象:

    package com.github.zhgxun.learn.common.bean;

    import com.google.gson.annotations.SerializedName;
    import lombok.Data;

    import java.util.List;

    @Data
    public class LogisticsTraceBean {

    // 标识属于快刀云回调产生的信息
    @SerializedName("iskuaidaoyun")
    private int isKuaidaoyun = 1;
    
    // 快递公司编码, go已经做过一次映射, 需要同步, 未做映射的保留原样, 需要补充到go代码中
    @SerializedName("shippercode")
    private String shipperCode;
    
    @SerializedName("ebussinessid")
    private String ebussinessId = "";
    
    // 格式为 callback := fmt.Sprintf("%v-%v-%v", deliveryId, pid, express)
    // ExpressSn 快递单号
    // DeliveryId 需要查询ShopDelivery表主键
    // pid 查看go代码, 查询 kuaidi100 的逻辑其实并没有处理 pid, 故 pid=0
    @SerializedName("ordercode")
    private String orderCode;
    
    // 快递单号
    @SerializedName("logisticcode")
    private String logisticCode;
    
    private boolean success = false;
    
    private String reason;
    
    // 快递状态
    // "在途中", "已发货", "疑难件", "已签收", "退签", "派件中", "退回"
    private String state;
    
    // 同 orderCode
    private String callback;
    
    // 回调操作时间, 当前时间戳
    @SerializedName("callback_time")
    private Long callbackTime = System.currentTimeMillis() / 1000;
    
    @SerializedName("subscribe_time")
    private int subscribeTime = 0;
    
    // 快递跟踪信息
    private List<TraceBean> traces;

    }
    嵌套对象:

    package com.github.zhgxun.learn.common.bean;

    import com.google.gson.annotations.SerializedName;
    import lombok.Data;

    @Data
    public class TraceBean {

    public TraceBean() {
    
    }
    
    public TraceBean(String acceptStation, String acceptTime) {
        this.acceptStation = acceptStation;
        this.acceptTime = acceptTime;
    }
    
    // 快递链路信息, 例如 签收成功, 签收人: 杨凯
    @SerializedName("acceptstation")
    private String acceptStation;
    
    // 当前记录时间 2017-08-16 11:09:01
    @SerializedName("accepttime")
    private String acceptTime;

    }
    对象都是用 gson @SerializedName 标识了序列化的期望。

    测试代码
    package com.github.zhgxun.learn.mongo;

    import com.github.zhgxun.learn.common.bean.LogisticsTraceBean;
    import com.github.zhgxun.learn.common.bean.TraceBean;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.query.Criteria;
    import org.springframework.data.mongodb.core.query.Query;
    import org.springframework.data.mongodb.core.query.Update;
    import org.springframework.test.context.junit4.SpringRunner;

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

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class CheckSerialTest {

    @Autowired
    private MongoTemplate mongoTemplate;
    
    @Test
    public void upsert() {
        List<TraceBean> beans = new ArrayList<>();
        beans.add(new TraceBean("北京亦庄发出", "2019-04-01"));
        beans.add(new TraceBean("北京亦庄出库", "2019-04-02"));
        beans.add(new TraceBean("北京昌平收货", "2019-04-03"));
        beans.add(new TraceBean("北京昌平签收", "2019-04-04"));
    
        LogisticsTraceBean bean = new LogisticsTraceBean();
        bean.setShipperCode("jd");
        bean.setOrderCode("1-2-3");
        bean.setLogisticCode("V0123");
        bean.setReason("");
        bean.setState("已签收");
        bean.setCallback("1-2-3");
        bean.setTraces(beans);
    
        Query query = new Query(Criteria.where("callback").is(bean.getCallback()));
        Update update = new Update();
        update.set("iskuaidaoyun", 1);
        // 映射到 MapCode
        update.set("shippercode", bean.getShipperCode());
        // ebussinessid 默认空
        update.set("ebussinessid", bean.getEbussinessId());
        // ordercode
        update.set("ordercode", bean.getOrderCode());
        // logisticcode 快递单号
        update.set("logisticcode", bean.getLogisticCode());
        // success = false
        update.set("success", false);
        // reason 默认空
        update.set("reason", "");
        // state 快递状态
        update.set("state", bean.getState());
        // callback 同 ordercode
        update.set("callback", bean.getCallback());
        // callback_time 当前 UNIX 时间戳
        update.set("callback_time", bean.getCallbackTime());
        // subscribe_time 默认0
        update.set("subscribe_time", 0);
        // traces 快递链路信息
        update.set("traces", bean.getTraces());
    
        System.out.println(mongoTemplate.upsert(query, update, LogisticsTraceBean.class, "kuaidibird"));
    }

    }
    尝试的方法
    编写转换器类:

    package com.github.zhgxun.learn.common.converter;

    import com.github.zhgxun.learn.common.bean.TraceBean;
    import org.bson.Document;
    import org.springframework.core.convert.converter.Converter;

    public class MongoSerialConverter implements Converter {

    @Override
    public TraceBean convert(Document source) {
        System.out.println("Source: " + source.toJson());
        Document document = (Document) source.get("traces");
        System.out.println("Document: " + document.toString());
        return null;
    }

    }
    启动类中加入 Bean 注入转换器,但不生效。

    @Bean
    public MongoCustomConversions mongoCustomConversions() {

    System.out.println("Mongo转换器...");
    return new MongoCustomConversions(Arrays.asList(new MongoSerialConverter()));

    }
    期望结果
    在不改变 MongoTemplate 使用方式,即是测试用例中的默认模板使用外,如何使属性是对象是也能按期望进行序列化。

    2019-07-17 23:32:45
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
MongoDB多数据中心的方案选型之路 立即下载
阿里云MongoDB云服务构建 立即下载
饿了么高级架构师陈东明:MongoDB是如何逐步提高可靠性的 立即下载