完成 M220J 类(class)后,我尝试构建自己的应用程序和后端 API,以进一步了解 Mongo Java 驱动程序,但遇到了阻碍。
上下文
我正在创建一个书签管理应用程序,并使用 Mongo 驱动程序和 Spring Boot 用 Java 重建后端。在 .find() 之后使用 .iterator() 或 .into() 查询我的 Atlas 数据库时,会出现错误。在 .find() 之后使用 .first() 时,不会出现错误。
我的 pom.xml 包含 mongodb-driver-sync 版本 4.2.2。我使用的是 Java 15.0.1。
文件夹集合使用 CodecRegistry,与 MongoDB 大学类(class) M220J 的 mflix 应用程序中创建用户或 session 集合的方式非常相似,这意味着对foldersCollection的查询应返回文件夹类型的文档。我已经验证数据在数据库和Folder.java类中具有相同的字段。
代码
在代码中,user_id 字段当前在文件夹文档中存储为字符串,而不是 ObjectId(充当外键),这不会导致错误。 .into() 技巧取自 this article talking about Mongo and Java Pojos.
这是我当前的实现,但是它不起作用。
// Returns an array of folders, given a user id
public List<Folder> getFolders(String id) {
if (id == null || id.isEmpty()) return null;
List<Folder> folders = foldersCollection.find(new Document("user_id", id)).into(new ArrayList<>());
return folders;
}
此代码也不起作用,它在 .find() 之后使用 .iterator(),并排除 id 来获取所有文件夹。如果我在查询中包含 id,它也不起作用。
public List<Folder> getAllFolders(){
List<Folder> folders = new ArrayList<>();
foldersCollection.find().iterator().forEachRemaining(folders::add);
return folders;
}
我已经通过 Java 和 Postman 中的测试验证了此代码可以正常工作:
// Gets a folder from db given folder _id
public Folder getFolder(String id) {
if (id == null || id.isEmpty()) return null;
return foldersCollection.find(new Document("_id", new ObjectId(id))).first();
}
NoSuchMethodError:
当我使用 .into() 时,它看起来像是指向 .find() 方法,但我已经确认 .find() 在与 .first() 链接时有效,所以我不认为 .find () 是问题所在。使用 .iterator() 时也会出现同样的错误。
java.lang.NoSuchMethodError: 'com.mongodb.internal.operation.ExplainableReadOperation com.mongodb.internal.operation.SyncOperations.find(org.bson.conversions.Bson, java.lang.Class, com.mongodb.internal.client.model.FindOptions)'
at com.mongodb.client.internal.FindIterableImpl.asReadOperation(FindIterableImpl.java:236)
at com.mongodb.client.internal.FindIterableImpl.asReadOperation(FindIterableImpl.java:40)
at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
at com.mongodb.client.internal.MongoIterableImpl.forEach(MongoIterableImpl.java:121)
at com.mongodb.client.internal.MongoIterableImpl.into(MongoIterableImpl.java:130)
at com.bookmarkd.api.daos.FolderDao.getFolders(FolderDao.java:46)
at com.bookmarkd.FolderTest.GetFolders(FolderTest.java:50) <31 internal lines>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) <9 internal lines>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) <23 internal lines>
最后,这是我的文件夹类和 Atlas 数据库中一些文档的图像:
public class Folder {
@BsonId
@JsonIgnore
private ObjectId oid;
@JsonProperty("_id")
@BsonIgnore
private String id;
@JsonProperty("user_id")
private String userId;
private String name;
private String icon;
private boolean shareable;
// Constructor, getters, and setters...
}
An image of a few Folder documents in the foldersCollection
非常感谢任何调试此问题的帮助!
附加代码/问题解释:
(虽然这使得帖子很长,但我认为在这里查看所有代码比从 Github 存储库查看更容易。)
也许我把事情复杂化了,但我正在尝试学习和使用 Spring Boot MVC。有一个FolderController 处理Http 请求,它调用FolderService,后者调用在Atlas 集群上执行CRUD 方法的FolderDao。所有这些文件都存储在各自的包中: Controller 、服务、daos、模型和配置。
FolderDao 扩展了一个 AbstractDao 类,该类使用从 @Autowired FoldDao 构造函数接收的值来设置客户端和数据库。
最后,MongoDBConfiguration 类配置设置并连接到 Atlas 集群。我在这里配置了PojoRegistry,as shown in this example 。我相信这个类实际上是在Application.java中的@SpringBootApplication启动后立即运行的。 mflix 应用程序中就是这样做的。您可以看到a completed mflix app here供引用。
也许错误来自 Atlas?我的 M0 免费层集群是版本 4.4.4,但我在完成 M220J 类(class)时没有遇到任何问题,其中此逻辑是使用 mflix 实现的。
以下是每个类的完整代码,按照我上面描述的顺序排列:
文件夹 Controller
package com.bookmarkd.api.controllers;
import com.bookmarkd.api.models.Folder;
import com.bookmarkd.api.services.FolderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin(origins = "*")
@RequestMapping("/api/folders")
@RestController
public class FolderController {
@Autowired
FolderService folderService;
public FolderController() { super(); }
public void getFolders() {}
// Get all folders, given the user id
@GetMapping("")
public ResponseEntity getFoldersByUserId(@RequestParam(value = "userid", required = false) String folderId) {
List<Folder> folders = folderService.getFolders(folderId);
if (folders == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
return ResponseEntity.status(HttpStatus.OK).body(folders);
}
// Get a single public folder, given the folder id
@GetMapping("/{id}")
public ResponseEntity getFolder(@PathVariable(value = "id") String folderId) {
Folder folder = folderService.getFolder(folderId);
if (folder == null) return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
return ResponseEntity.status(HttpStatus.OK).body(folder);
}
public void addFolder() {}
public void updateFolder() {}
public void deleteFolder() {}
}
文件夹服务
package com.bookmarkd.api.services;
import com.bookmarkd.api.daos.FolderDao;
import com.bookmarkd.api.models.Folder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import java.util.List;
@Configuration
@Service
public class FolderService {
@Autowired
private FolderDao folderDao;
public FolderService() {
super();
}
public List<Folder> getFolders(String id) {
return folderDao.getFolders(id);
}
public Folder getFolder(String id) {
return folderDao.getFolder(id);
}
// Add folder, update folder, delete folder, to-be-implemented later...
}
文件夹Dao
package com.bookmarkd.api.daos;
import com.bookmarkd.api.models.Folder;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Configuration
public class FolderDao extends AbstractDao {
private final MongoCollection<Folder> foldersCollection;
@Autowired
public FolderDao(MongoClient mongoClient, @Value("${spring.mongodb.database}") String databaseName) {
super(mongoClient, databaseName);
foldersCollection = db.getCollection("folders", Folder.class);
}
// Returns an array of folders, given a user _id
public List<Folder> getFolders(String id) {
if (id == null || id.isEmpty()) return null;
List<Folder> folders = foldersCollection.find(new Document("user_id", id)).into(new ArrayList<>());
// List<Folder> folders = new ArrayList<>();
// foldersCollection.find(new Document("user_id", id)); //.iterator().forEachRemaining(folders::add);
return folders;
}
// Gets a folder from db given folder _id
public Folder getFolder(String id) {
if (id == null || id.isEmpty()) return null;
return foldersCollection.find(new Document("_id", new ObjectId(id))).first();
}
}
抽象道
package com.bookmarkd.api.daos;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public abstract class AbstractDao {
protected String LBV_DATABASE;
protected MongoDatabase db;
protected MongoClient mongoClient;
protected AbstractDao(MongoClient mongoClient, String databaseName) {
this.mongoClient = mongoClient;
LBV_DATABASE = databaseName;
this.db = this.mongoClient.getDatabase(LBV_DATABASE);
}
}
MongoDBConfiguration(这是我注册 Pojo 编解码器的位置,它适用于 User 模型和folderCollection.find().first() 实现)
package com.bookmarkd.api.config;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.WriteConcern;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
// Used to configure connection to Atlas cluster
@Configuration
@Service
public class MongoDBConfiguration {
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public MongoClient mongoClient(@Value("${spring.mongodb.uri}") String connectionString) {
CodecRegistry pojoCodecRegistry = fromRegistries(
MongoClientSettings.getDefaultCodecRegistry(),
fromProviders(PojoCodecProvider.builder().automatic(true).build())
);
ConnectionString connString = new ConnectionString(connectionString);
WriteConcern writeConcern = WriteConcern.MAJORITY; //.withWTimeout(2500, TimeUnit.MILLISECONDS);
MongoClientSettings settings = MongoClientSettings.builder()
.writeConcern(writeConcern)
.applyConnectionString(connString)
.codecRegistry(pojoCodecRegistry)
.build();
MongoClient mongoClient = MongoClients.create(settings);
return mongoClient;
}
}
希望所有代码的完整 View 能让您深入了解出了什么问题!
最佳答案
事实证明,我需要三个 Mongo 特定的依赖项,且版本相同。
将 org.mongo:bson:4.2.3
和 org.mongo.mongodb-driver-code:4.2.3
添加到现有的 org.mongodb pom.xml 中的 -driver-sync:4.2.3
依赖项解决了该问题(我之前使用的是 4.1.2 版本的 mongodb-driver-core 和 mongodb-driver-bson)。
哇,这样的压力仅仅涉及依赖性问题!不幸的是,文档不清楚是否需要全部三个,我认为您只需要 mongodb-driver-sync。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bookmarkd</groupId>
<artifactId>LBV</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>LBV</name>
<description>Bookmarkd Java REST API backend try 2</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-sync -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-core -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<version>4.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mongodb/bson -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
<version>4.2.3</version>
</dependency>
</dependencies>
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
</project>
关于java - MongoDB Java 驱动程序 4.2.2 - 将 .iterator 或 .into 与 .find 链接时出现 java.lang.noSuchMethodError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67023553/