Vertx 中访问 MongoDB 数据库

MongoDB 是时下非常流行的非关系型数据库, Vertx 也对它提供了很好的支持。本文演示如何用 Vertx 的 MongoDB client

加入依赖

在项目的 pom.xml 文件中,添加 MongoDB client。

1
2
3
4
5
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mongo-client</artifactId>
<version>3.9.2</version>
</dependency>

获取连接实例

在 Vertx MongoDB Client 中, 对 MongoDB 的访问都包装在 MongoClient 这个类中。因此我们首先需要获取 MongoClient。 在这里,我们设计一个简单的单例来封装这部分的逻辑,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Slf4j
public class MongoDB {

private JsonObject config = null;
private Vertx vertx = null;
private JsonObject mongoconfig = new JsonObject();

private static final MongoDB instance = new MongoDB();

public MongoDB() {

}

public static MongoDB getInstance() {
return instance;
}

public MongoDB init(Vertx vertx, JsonObject config) {
this.vertx = vertx;
this.config = config;

mongoconfig.put("connection_string", config.getString("connStr"));
mongoconfig.put("db_name", config.getString("dbName"));
mongoconfig.put("username", config.getString("username"));
mongoconfig.put("password", config.getString("password"));
mongoconfig.put("authSource", config.getString("authSource"));

return this;
}

public MongoClient getClient() {

return MongoClient.createShared(vertx, mongoconfig, MongoDefault.MONGODB_SHARE_POOL_NAME);
}
}

MONGODB_SHARE_POOL_NAME 是定义在 MongoDefault 这个类中的一个字符串常量,用来指定共享名,这样,在同一个 Vertx 的上下文中,就可以使用 MongoClient 的共享池。

定义抽象实体类

在 Vertx 中, MongoDB client 可以直接对 JsonObject (Vertx的”一等公民”)进行操作,但在企业开发中,我们往往习惯于操作实体类,因此在这里定义一个抽象的实体类来包装 JsonObject 和实体之间这转换。 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class AbstractMongoModel {

private String _id;

private String createDate;

public String get_id() {
return _id;
}

public void set_id(String _id) {
this._id = _id;
}

public String getCreateDate() {
return createDate;
}

public void setCreateDate(String createDate) {
this.createDate = createDate;
}

@JsonIgnore
public JsonObject getPKQuery() {
JsonObject query = new JsonObject();
query.put("_id", _id);
return query;
}

public JsonObject toJson() {

JsonObject json = JsonObject.mapFrom(this);
return json;
}

public static <T> T fromJson(JsonObject json, Class<T> t) {

T o = json.mapTo(t);
return o;
}

public static <T> List<T> fromJsonArray(JsonArray jsona, Class<T> t) {

List<T> rc = new ArrayList<T>();
List<T> o = jsona.getList();
for(T tt: o){
T oo = ((JsonObject) tt).mapTo(t);
rc.add(oo);
}
return rc;
}

}

定义回调接口

因为在 Vertx 中的 API 都设计为以回调的方法来返回值,为后续进行统一处理方法,我们定义要给回调的包装接口:

1
2
3
4
public interface MResultHandler<T> {

public void handle(MResult<T> mResult);
}

和一个对应的类:

1
2
3
4
5
6
7
8
@Data
@NoArgsConstructor
public class MResult<T> {

private boolean succ = false;
private Throwable exception = null;
private T data;
}

定义查询方法

首先,定义一个通用的,通过查找条件 (query) 来查询一整个对象(文档,记录)的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected void findOne(JsonObject query, MResultHandler<T> handler) {

MongoClient mongo = MongoDB.getInstance().getClient();

mongo.findOne(getRepositoryName(), query, null, h -> {
MResult<T> mResult = new MResult<>();
if (h.succeeded()) {
JsonObject obj = h.result();
if (obj != null) {
T t = (T) T.fromJson(obj, entityClass);
postMapper(obj, t);
mResult.setSucc(true);
mResult.setData(t);
}
}
handler.handle(mResult);

mongo.close();
});

}

稍加包装,就可以得到要给通过主键(“_id”)来查找一整个对象(文档,记录)的方法:

1
2
3
4
5
6
7
public void findByPK(String pk, MResultHandler<T> handler) {

JsonObject query = new JsonObject();
query.put("_id", pk);

findOne(query, handler);
}

定义新增方法

在新增中,可以考虑由 MongoDB 自己生成 _id 的情况和用户指定的情况, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void insert(T t, boolean removeId, MResultHandler<String> mh) {

MongoClient mongo = MongoDB.getInstance().getClient();

JsonObject json = t.toJson();

postToJson(json, t);

if (removeId) {
json.remove("_id");
}
json.put("createDate", DateTimeUtil.getCurrentDateTime());

mongo.insert(getRepositoryName(), json, h -> {

MResult<String> result = new MResult<>();
if (h.succeeded()) {
result.setSucc(true);
result.setData(h.result());
} else {
log.error("Failed to insert object: ", h.cause());
}
mh.handle(result);
mongo.close();
});

}

定义更新方法

在更新中,我们通过判断影响的文档(记录)数来判断更新是否成功, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static final UpdateOptions DEFAULT_UPDATE_OPTIONS = new UpdateOptions(false, false);
protected void update(JsonObject query, JsonObject update, MResultHandler<JsonObject> handler) {

JsonObject setPhase = new JsonObject();
setPhase.put("$set", update);

MongoClient mongo = MongoDB.getInstance().getClient();

mongo.updateCollectionWithOptions(getRepositoryName(), query, setPhase, DEFAULT_UPDATE_OPTIONS, h -> {

MResult<JsonObject> mResult = new MResult<>();
if (h.succeeded()) {
MongoClientUpdateResult r = h.result();
if (r.getDocMatched() == 1) {
mResult.setSucc(true);
}
} else {
log.error("Update failed: ", h.cause());
}
handler.handle(mResult);

mongo.close();
});

}

定义删除方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void remove(JsonObject query, MResultHandler<JsonObject> handler) {

MongoClient mongo = MongoDB.getInstance().getClient();

mongo.removeDocumentsWithOptions(getRepositoryName(), query, null, h -> {

MResult<JsonObject> mResult = new MResult<>();
if (h.succeeded()) {
MongoClientDeleteResult r = h.result();
if (r.getRemovedCount() > 0) {
mResult.setSucc(true);
}
} else {

}
handler.handle(mResult);

mongo.close();
});

}

本文标题:Vertx 中访问 MongoDB 数据库

文章作者:晨星

发布时间:2020年08月31日 - 09:08

最后更新:2020年09月16日 - 08:09

原始链接:https://www.mls-tech.info/java/vertx-access-mongodb/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。