MongoDB 不序列化Java属性类问题

发布于 2022-09-11 18:58:27 字数 7158 浏览 24 评论 0

环境

Spring boot 是 <version>2.1.0.RELEASE</version>

<!-- mongo -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

<!--
    https://mvnrepository.com/artifact/org.projectlombok/lombok
-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
    <scope>provided</scope>
</dependency>

<!--
    单元测试相关
-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

对象不完全序列化

最近在项目中存储数据到 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<Document, TraceBean> {

    @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 使用方式,即是测试用例中的默认模板使用外,如何使属性是对象是也能按期望进行序列化。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文