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 使用方式,即是测试用例中的默认模板使用外,如何使属性是对象是也能按期望进行序列化。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。