文章目录
前言
最近在设计一个针对mongodb数据操作的客户端,以配合自己设计的DB接点一同使用。
一、为什么要将Document转换为bytes?
在实际开发中,开发一个针对mongodb的一个客户端,该客户端与DB接点进程(自己开发的进程)进行通讯,为了让开发客户端操作数据库与直接操作DB进程操作一样的便利性,选择直接操作document,就好比redis客户端一样,如:jedis等
但是发现一个问题,虽然document可以直接转换string类型,但是相对比较耗费流量,并且不能跨语言使用,所以设计一个document序列化和反序列转换为bytes的工具就是我的目的
二、工具类实现
1.引入库:
dependencies {
//打印异常库(可以不添加)
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
//MongoDB 依赖库
implementation group: 'org.mongodb', name: 'mongodb-driver-core', version: '3.11.0'
implementation group: 'org.mongodb', name: 'bson', version: '3.11.0'
implementation group: 'org.mongodb', name: 'mongodb-driver', version: '3.11.0'
}
以下代码使用了lombok插件,具体插件安装请自行安装,不作叙述,引用 log4j2日志库
2.bytes序列化转换为document
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class DocumentInputStream {
ByteArrayInputStream mInput = null;
DataInputStream mData = null;
public DocumentInputStream(byte[] data) {
this.mInput = new ByteArrayInputStream(data);
this.mData = new DataInputStream(this.mInput);
}
private DocumentInputStream() {
}
public Document dataToDocument() {
Document doc = new Document();
try {
byte type = this.mData.readByte();
if (type != DataType.IS_DOCUMENT_HEAD) {
throw new IllegalArgumentException(" data head is not IS_DOCUMENT_HEAD");
}
byte valueType = this.mData.readByte();
if (valueType == DataType.IS_EMPTY_DOCUMENT) {
this.mData.readByte();
return new Document();
}
for(; valueType != DataType.IS_DOCUMENT_END && !this.isEnd(); valueType = this.mData.readByte()) {
String key = this.readSmallString();
if (DataType.IS_BYTE == valueType) {
doc.put(key, this.mData.readByte());
} else if (DataType.IS_SHORT == valueType) {
doc.put(key, this.mData.readShort());
} else if (DataType.IS_INT == valueType) {
doc.put(key, this.mData.readInt());
} else if (DataType.IS_FLOAT == valueType) {
doc.put(key, this.mData.readFloat());
} else if (DataType.IS_DOUBLE == valueType) {
doc.put(key, this.mData.readDouble());
} else if (DataType.IS_LONG == valueType) {
doc.put(key, this.mData.readLong());
} else if (DataType.IS_STRING == valueType) {
doc.put(key, this.readShortString());
} else if (DataType.IS_BYTES == valueType) {
doc.put(key, this.readBytes());
} else if (DataType.IS_BOOLEAN == valueType) {
doc.put(key, this.mData.readBoolean());
} else if (DataType.IS_LIST == valueType) {
doc.put(key, this.readList());
} else if (DataType.IS_DOCUMENT == valueType) {
doc.put(key, this.dataToDocument());
}
else
{
throw new IOException(" An error occurred,please check the document key="+key);
}
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return doc;
}
@SuppressWarnings("unchecked")
List readList() throws IOException {
int nCount = this.mData.readInt();
if (nCount == 0) {
return new ArrayList();
} else {
byte type = this.mData.readByte();
if (DataType.IS_NO_SUPPORT == type) {
return new ArrayList();
} else {
List l = new ArrayList();
for(int i = 0; i < nCount; ++i) {
if (DataType.IS_BYTE == type) {
l.add(this.mData.readByte());
} else if (DataType.IS_SHORT == type) {
l.add(this.mData.readShort());
} else if (DataType.IS_INT == type) {
l.add(this.mData.readInt());
} else if (DataType.IS_FLOAT == type) {
l.add(this.mData.readFloat());
} else if (DataType.IS_DOUBLE == type) {
l.add(this.mData.readDouble());
} else if (DataType.IS_LONG == type) {
l.add(this.mData.readLong());
} else if (DataType.IS_STRING == type) {
l.add(this.readShortString());
} else if (DataType.IS_BYTES == type) {
l.add(this.readBytes());
} else if (DataType.IS_BOOLEAN == type) {
l.add(this.mData.readBoolean());
} else if (DataType.IS_LIST == type) {
l.add(this.readList());
}else if (DataType.IS_DOCUMENT == type) {
l.add(this.dataToDocument());
}
}
return l;
}
}
}
public boolean isEnd() {
try {
return this.mData.available() <= 0;
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
return false;
}
}
String readString(int nLen) throws IOException {
byte[] data = new byte[nLen];
this.mData.read(data);
String outData = new String(data);
return outData;
}
String readShortString() throws IOException {
short b = this.mData.readShort();
return this.readString(b);
}
String readSmallString() throws IOException {
byte b = this.mData.readByte();
return this.readString(b);
}
public byte[] readBytes(int nLen) throws IOException {
byte[] data = new byte[nLen];
this.mData.read(data);
return data;
}
public byte[] readBytes() throws IOException {
int nLen = this.mData.readInt();
return this.readBytes(nLen);
}
}
3 document 反序列化bytes
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.bson.Document;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Slf4j
public class DocumentOutputStream {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(out);
public void packDocument(Document document)
{
try {
dataOutputStream.writeByte(DataType.IS_DOCUMENT_HEAD);
Set<Map.Entry<String, Object>> set = document.entrySet();
if(set.size()==0)
{
dataOutputStream.writeByte(DataType.IS_EMPTY_DOCUMENT);
dataOutputStream.writeByte(DataType.IS_DOCUMENT_END);
return;
}
for(Map.Entry<String,Object>entry:set)
{
if(entry.getValue() instanceof Byte )
{
byte value = ((Byte) entry.getValue()).byteValue();
dataOutputStream.writeByte(DataType.IS_BYTE);
writeSmallString(entry.getKey());
dataOutputStream.writeByte(value);
}
else if(entry.getValue() instanceof Short)
{
short value = ((Short) entry.getValue()).shortValue();
dataOutputStream.writeByte(DataType.IS_SHORT);
writeSmallString(entry.getKey());
dataOutputStream.writeShort(value);
}
else if(entry.getValue() instanceof Integer)
{
int value = ((Integer) entry.getValue()).intValue();
dataOutputStream.writeByte(DataType.IS_INT);
writeSmallString(entry.getKey());
dataOutputStream.writeInt(value);
}
else if(entry.getValue() instanceof Float)
{
float value = ((Float) entry.getValue()).floatValue();
dataOutputStream.writeByte(DataType.IS_FLOAT);
writeSmallString(entry.getKey());
dataOutputStream.writeFloat(value);
}
else if(entry.getValue() instanceof Double)
{
double value = ((Double) entry.getValue()).doubleValue();
dataOutputStream.writeByte(DataType.IS_DOUBLE);
writeSmallString(entry.getKey());
dataOutputStream.writeDouble(value);
}
else if(entry.getValue() instanceof Long)
{
long value = ((Long) entry.getValue()).longValue();
dataOutputStream.writeByte(DataType.IS_LONG);
writeSmallString(entry.getKey());
dataOutputStream.writeLong(value);
}
else if(entry.getValue() instanceof String)
{
String value = (String) entry.getValue();
dataOutputStream.writeByte(DataType.IS_STRING);
writeSmallString(entry.getKey());
writeShortString(value);
}
else if(entry.getValue() instanceof byte[])
{
byte[] value = (byte[])entry.getValue();
dataOutputStream.writeByte(DataType.IS_BYTES);
writeSmallString(entry.getKey());
writeBytes(value);
}
else if(entry.getValue() instanceof Boolean)
{
boolean value = ((Boolean) entry.getValue()).booleanValue();
dataOutputStream.writeByte(DataType.IS_BOOLEAN);
writeSmallString(entry.getKey());
dataOutputStream.writeBoolean(value);
}
else if(entry.getValue() instanceof Document)
{
Document myDoc = (Document)entry.getValue();
dataOutputStream.writeByte(DataType.IS_DOCUMENT);
writeSmallString(entry.getKey());
packDocument(myDoc);
}
else if(entry.getValue() instanceof List)
{
List list = ((List) entry.getValue());
dataOutputStream.writeByte(DataType.IS_LIST);
writeSmallString(entry.getKey());
writeList(list);
}
else
{
//throw new IOException("key ="+entry.getKey()+" dont found type when packed document");
}
}
dataOutputStream.writeByte(DataType.IS_DOCUMENT_END);
}catch (IOException e)
{
log.error(ExceptionUtils.getStackTrace(e));
}
}
void writeList(List list) throws IOException
{
dataOutputStream.writeInt(list.size());
if(list.size() !=0)
{
Object o = list.get(0);
if(o instanceof Byte)
{
dataOutputStream.writeByte(DataType.IS_BYTE);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeByte((byte) list.get(i));
}
}
else if(o instanceof Short)
{
dataOutputStream.writeByte(DataType.IS_SHORT);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeShort((short)list.get(i));
}
}
else if(o instanceof Integer)
{
dataOutputStream.writeByte(DataType.IS_INT);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeInt((int)list.get(i));
}
}
else if(o instanceof Float)
{
dataOutputStream.writeByte(DataType.IS_FLOAT);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeFloat((float)list.get(i));
}
}
else if(o instanceof Double)
{
dataOutputStream.writeByte(DataType.IS_DOUBLE);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeDouble((double)list.get(i));
}
}
else if(o instanceof Long)
{
dataOutputStream.writeByte(DataType.IS_LONG);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeLong((long)list.get(i));
}
}
else if(o instanceof String)
{
dataOutputStream.writeByte(DataType.IS_STRING);
for(int i=0; i<list.size(); i++)
{
writeShortString((String)list.get(i));
}
}
else if(o instanceof byte[])
{
dataOutputStream.writeByte(DataType.IS_BYTES);
for(int i=0; i<list.size(); i++)
{
writeBytes((byte[]) list.get(i));
}
}
else if(o instanceof Boolean)
{
dataOutputStream.writeByte(DataType.IS_BOOLEAN);
for(int i=0; i<list.size(); i++)
{
dataOutputStream.writeBoolean((boolean)list.get(i));
}
}
else if(o instanceof Document)
{
dataOutputStream.writeByte(DataType.IS_DOCUMENT);
for(int i=0; i<list.size(); i++)
{
packDocument((Document) list.get(i));
}
}
else
{
//throw new IOException(" An error occurred,please check the document key");
//dataOutputStream.writeByte(DataType.IS_NO_SUPPORT);
}
}
}
void writeSmallString(String value)
{
try {
byte[] data = value.getBytes();
dataOutputStream.writeByte(data.length);
dataOutputStream.write(data);
}catch (IOException e)
{
log.error(ExceptionUtils.getStackTrace(e));
}
}
void writeShortString(String value)
{
try {
byte[] data = value.getBytes();
dataOutputStream.writeShort(data.length);
dataOutputStream.write(data);
}catch (IOException e)
{
log.error(ExceptionUtils.getStackTrace(e));
}
}
void writeBytes(byte[] value)
{
try {
dataOutputStream.writeInt(value.length);
dataOutputStream.write(value,0,value.length);
}catch (IOException e)
{
log.error(ExceptionUtils.getStackTrace(e));
}
}
public byte[] getBytes()
{
return out.toByteArray();
}
}
4 定义DataType类
/**
*对于mongodb ObjectId(MongoDB默认的id) 做了屏蔽,一般情况下我们是不需要MongoDB中默认的*ObjectID的,因为会自己设置索引,如果需要,请添加ObjectID类型,并在序列化和反序列化接口中添加
*如果以下类型不满足,那么也请自行添加
**/
public class DataType {
public static byte IS_BYTE = 100;
public static byte IS_SHORT = 101;
public static byte IS_INT = 102;
public static byte IS_LONG = 103;
public static byte IS_FLOAT = 104;
public static byte IS_DOUBLE = 105;
public static byte IS_STRING = 106;
public static byte IS_BYTES = 107;
public static byte IS_BOOLEAN = 108;
public static byte IS_DOCUMENT_HEAD = 109;
public static byte IS_DOCUMENT_END = 110;
public static byte IS_DOCUMENT = 111;
public static byte IS_EMPTY_DOCUMENT = 112;
public static byte IS_LIST = 113;
//public static byte IS_DOCUMENT_ARRAY = 114;
public static byte IS_NO_SUPPORT = 125;
}
5 开发环境
工程环境 window10. gradle-6.8.3 ,编辑器idea 2019.3.4