MongoTemplate配置的重构如下:
1. 首先,在`application.properties`文件中添加MongoDB的连接信息:
```properties
spring.data.mongodb.uri=mongodb://root:password@ip1:27000,ip2:27000/test
```
2. 接下来,在Spring Boot项目中创建一个配置类,例如`MongoConfig`,并实现`MongoDatabaseFactoryBean`接口:
```java
import com.mongodb.ConnectionString;
import com.mongodb.client.MongoClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
@Configuration
public class MongoConfig {
@Value("${spring.data.mongodb.uri}")
private String connectionString;
@Bean(name = "mongoTemplate")
public MongoTemplate mongoTemplate() {
ConnectionString connString = new ConnectionString(connectionString);
MongoClients clients = MongoClients.create(connString);
DbRefResolver dbRefResolver = defaultDbRefResolver();
MappingMongoConverter mappingConverter = defaultMappingMongoConverter(dbRefResolver);
MongoDatabaseFactoryBean databaseFactory = new MongoDatabaseFactoryBean(clients, null);
databaseFactory.setName("mongo");
databaseFactory.setEncoding("UTF-8");
databaseFactory.setDropTargetDirs("true");
databaseFactory.setDbRefResolver(dbRefResolver); //设置默认的引用解析器
databaseFactory.setMappingConverter(mappingConverter); //设置默认的映射转换器
databaseFactory.afterPropertiesSet(); //初始化后置处理器,如果有的话。注意此方法调用必须在afterPropertiesSet方法之后!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
return new MongoTemplate(databaseFactory);
}
@Bean(name = "defaultDbRefResolver")
public DefaultDbRefResolver defaultDbRefResolver() {
return new DefaultDbRefResolver(); //返回默认的引用解析器实例。如果你需要自定义引用解析器,可以在这里进行配置。如果不需要,直接使用上面的dbRefResolver即可。
}
@Bean(name = "defaultMappingMongoConverter")
public MappingMongoConverter defaultMappingMongoConverter(@Qualifier("defaultDbRefResolver") DbRefResolver dbRefResolver) { //返回默认的映射转换器实例。如果你需要自定义映射转换器,可以在这里进行配置。如果不需要,直接使用上面的mappingConverter即可。但是,你需要自己实现一个MappingMongoConverter,并将上述的dbRefResolver注入到这个实例中,以确保它能够正确地工作。下面是一个示例代码:
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.stereotype.Component;
import com.mongodb.client.model.Filters; //需要添加这个库才能使用Filters枚举类型。可以在pom文件中添加以下依赖:
```java
@Configuration@EnableMongoRepositories()
public class MongoTemplateConfig {
@Autowired
TimestampConverter timestampConverter;
private final String URI_PATTERN = "(mongodb.*:)(.*?)(@.+)";
@Bean
public MongoDatabaseFactory mongoDbFactory(MongoProperties properties) throws Exception {
final boolean match = ReUtil.isMatch(URI_PATTERN, properties.getUri());
final String newUri;
if (match) {
String password = ReUtil.extractMulti(URI_PATTERN, properties.getUri(), "$2");
final String passwordDecrypt = StringUtils.reverse(password);
newUri = StringUtils.replace(properties.getUri(), password, passwordDecrypt);
} else {
throw new BusiException(SystemFlag.BUSINESS_ERROR, "the Uri of mongodb parsed error");
}
ConnectionString connectionString = new ConnectionString(newUri);
return new SimpleMongoClientDatabaseFactory(connectionString);
}
@Bean
public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory factory,
@Qualifier("mongoCusConversions") CustomConversions conversions) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
mappingConverter.setCustomConversions(conversions);
// 不保存 _class
mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
return mappingConverter;
}
@Bean(name = "mongoCusConversions")
@Primary
public CustomConversions mongoCustomConversions() {
return new MongoCustomConversions(Arrays.asList(timestampConverter));
}
@Bean
@Primary
public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDbFactory,
MongoConverter converter) throws UnknownHostException {
return new MongoTemplate(mongoDbFactory, converter);
}
}
```
以下是重构后的代码:
```java
@EnableMongoRepositories(basePackages = "com.example.repository") // 表示支持Spring JPA,通过规范命名的接口实现简单的DB操作
public class MongoConfig implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 配置MongoDatabaseFactory,实现一个简单的配置文件解密过程
String configPath = "classpath:application-mongo.properties";
MongoClient mongoClient = null;
try {
mongoClient = new MongoClient(new ServerAddress("localhost", 27017));
DB db = mongoClient.getDB("test");
MongoDatabaseFactory mongoDbFactory = new SimpleMongoDbFactory(db);
ConfigurationSource configurationSource = new MapConfigurationSource(new Properties());
configurationSource.setConfiguration(new FileConfiguration(configPath));
mongoDbFactory.setConvertValuesToTypesIfPossible(true);
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(mongoDbFactory);
mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null)); // 取消每条记录生成一个"-class"的数据
conversionService = new DefaultConversionService(mappingMongoConverter);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mongoClient != null) {
mongoClient.close();
}
}
}
}
```
以下是重构后的内容:
```java
import org.springframework.data.mongodb.core.convert.Converter;
import java.time.LocalDateTime;
public class DateToString implements Converter
@Override
public String convert(LocalDateTime source) {
return source.toString() + 'Z';
}
}
// Direction: MongoDB <-- Java
public class StringToDate implements Converter
@Override
public LocalDateTime convert(String source) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
}
}
```
可以通过WritingConverter和ReadingConverter配置Document和Java对象相互转化。在实战中,例如一个博客系统,我们通过MongoDB存储用户的浏览记录。浏览记录的实体如下所示:
```java
public class BrowsingRecord {
private String userId; // 用户ID
private Date browseTime; // 浏览时间
// 其他属性...
}
```
根据提供的内容,这是一个名为VisitLogEntity的Java类,它实现了Serializable接口。这个类有一个静态常量serialVersionUID,用于序列化和反序列化时的版本控制。这个类有以下属性:id、pageId、viewerName、createDate、lastUpdateDate和viewCount。其中,viewCount默认值为1L。
针对这个场景,我们可以使用MongoTemplate进行基本的操作,如findOne、exists、find和findAndRemove。这些操作的基本用法是传入一个封装查询条件的对象Query,Java中映射的对象entityClass和MongoDB中对应的Document的名称。
以下是这些操作的示例代码:
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
public class VisitLogService {
@Autowired
private MongoTemplate mongoTemplate;
public
return mongoTemplate.findOne(query, entityClass);
}
public boolean exists(Query query) {
return mongoTemplate.exists(query, VisitLogEntity.class);
}
public
return mongoTemplate.find(query, entityClass);
}
public boolean findAndRemove(Query query, Class
return mongoTemplate.remove(query, VisitLogEntity.class) > 0;
}
}
```
在这个示例中,我们创建了一个名为VisitLogService的服务类,它使用了@Autowired注解注入了一个MongoTemplate实例。然后,我们定义了四个方法:findOne、exists、find和findAndRemove,分别对应MongoTemplate的四个基本操作。
在这段代码中,我们可以通过构建查询条件来查询某个用户某篇博客的访问次数。首先,我们需要创建一个`Query`对象,并添加查询条件,包括`pageId`和`viewerName`。然后,我们使用`mongoTemplate.find()`方法根据查询条件从数据库中查找符合条件的记录,并将其映射为`VisitLogEntity`类型的对象列表。
此外,这段代码还提供了一个名为`findAndModify`的方法,该方法用于更新符合查询条件的记录。它接受四个参数:`query`(查询条件),`update`(更新操作),`entityClass`(实体类类型)和`collectionName`(集合名称)。通过调用`findAndModify()`方法并传入这些参数,我们可以实现对数据库中符合条件的记录进行更新操作。
这段代码是一个用于更新和获取VisitLogEntity的方法。首先,它会创建一个查询条件,根据viewerName和pageId来查找VisitLogEntity。然后,通过mongoTemplate.exists()方法判断是否存在满足条件的记录。
如果存在满足条件的记录,那么它会创建一个Update对象,将viewCount字段加1,并设置lastUpdateDate字段为当前时间。接着,使用mongoTemplate.findAndModify()方法来更新查询到的记录,并返回更新后的记录。
如果不存在满足条件的记录,那么它会创建一个新的VisitLogEntity对象,并设置createDate和lastUpdateDate字段为当前时间。最后,使用mongoTemplate.save()方法将新的记录保存到数据库,并返回该记录。
保存操作主要包括insert和save方法。这两个方法都没有返回值,但它们之间有一些区别:
1. 当插入单个记录时,如果新数据的主键已经存在,insert方法会报错DuplicateKeyException提示主键重复,不保存当前数据;而save方法会根据当前数据对存量数据进行更新。
2. 在进行批量保存时,insert方法可以一次性插入一个列表,不需要遍历;而save方法需要遍历列表进行一个一个的插入。因此,insert方法的效率要高很多。
以下是该方法的代码示例:
```java
/**
* 执行一次upsert操作。如果没有找到与查询条件匹配的文档,将创建一个新文档并通过组合查询文档和更新文档将其插入。
*
* @param query 用于选择要插入或更新的记录的查询文档
* @param update 包含更新对象或$操作符的更新文档,用于操作现有对象
* @param entityClass 要操作的POJO类
* @param collectionName 要在其中更新对象的集合名称
* @return WriteResult,允许您访问先前写入的结果
*/
WriteResult upsert(Query query, Update update, Class> entityClass, String collectionName);
该方法的功能是,如果存在与查询条件匹配的文档,则根据Update中的内容进行更新,如果不存在符合查询条件的内容,则根据查询条件和Update插入新的文档。
聚合查询MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。本文侧重于Java实现。
结合上述中的访问记录的场景,如果我们需要统计某个博主某个专栏下面所有文章的访问记录,包括访问总人数,访问总次数,以及每个访客对应的访问次数详情,并且要满足分页需求,那么我们需要用到MongoDB的聚合操作,具体实现如下所示:
```java
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.bson.conversions.Bson;
import java.util.ArrayList;
import java.util.List;
public class MongoDBAggregationExample {
public static void main(String[] args) {
// 连接到MongoDB数据库
MongoClient mongoClient = new MongoClient("localhost", 27017);
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection
// 定义聚合管道
List
pipeline.add(new Document("$match", new Document("author", "张三")
.append("category", "Java"))); // 根据博主和专栏筛选文档
pipeline.add(new Document("$group", new Document("_id", "$visitor") // 按访客分组
.append("totalVisitors", new Document("$sum", 1)) // 统计总访客数
.append("totalVisits", new Document("$sum", 1)))); // 统计总访问次数
pipeline.add(new Document("$project", new Document("_id", 0) // 不显示访客ID
.append("totalVisitors", "$totalVisitors") // 总访客数
.append("totalVisits", "$totalVisits"))); // 总访问次数
pipeline.add(new Document("$skip", 0) // 跳过前10条记录
.append("$limit", 10)); // 只显示最后10条记录
// 执行聚合查询
AggregateIterable
for (Document doc : result) {
System.out.println(doc.toJson());
}
}
}
```
重构后代码如下:
```java
public ResultEntity
Criteria criteria = Criteria.where("page_id").in(contentIds);
List
operations.add(Aggregation.match(criteria));
operations.add(Aggregation.group("viewer_name").sum("view_count").as("viewCount").first("viewer_name").as("viewerName"));
// 多线程处理提高响应速度
CountDownLatch latch = new CountDownLatch(3);
long totalRecord[] = {0L};
long[] count = {0L};
executor.execute(() -> count[0] = Optional.ofNullable(mongoTemplate.aggregate(Aggregation.newAggregation(operations), "visit_log", VisitRecordEntity.class))
.map(result -> result.getMappedResults()).map(mappedResult -> mappedResult.size()).orElse(0));
latch.countDown();
executor.execute(() -> totalRecord[0] = (long) Optional.ofNullable(mongoTemplate.aggregate(Aggregation.newAggregation(operations), "visit_log", Map.class))
.map(result -> result.getMappedResults()).map(mappedResult -> mappedResult.get(0)).map(map -> map.get("totalRecord")).orElse(0));
latch.countDown();
executor.execute(() -> recordEntities[0] = Optional.ofNullable(mongoTemplate.aggregate(agg, "visit_log", VisitRecordEntity.class))
.map(AggregationResults::getMappedResults).orElse(new ArrayList<>(0)));
latch.countDown();
try {
latch.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
ResultEntity
resultEntity.setItems(recordEntities[0]);
resultEntity.setTotalRecord(totalRecord[0]);
resultEntity.setTotalRow(count[0]);
return resultEntity;
}
```
总结:本文主要介绍了SpringBoot与MongoDB的整合方法,并结合博客系统访问记录,演示了MongoTemplate的基本用法。
正文:首先,我们简要了解一下Spring Boot和MongoDB。
Spring Boot是一个开源的Java框架,它简化了基于Spring框架的应用程序的创建、配置和部署过程。而MongoDB是一个高性能的NoSQL数据库,适用于存储大量非结构化数据。
接下来,我们将介绍如何在Spring Boot中整合MongoDB。
1. 添加依赖
在项目的pom.xml文件中,我们需要添加Spring Data MongoDB的依赖:
```xml
```
2. 配置MongoDB
在application.properties或application.yml文件中,我们需要配置MongoDB的连接信息:
```properties
# application.properties
spring.data.mongodb.uri=mongodb://username:password@localhost:27017/database_name
```
或者
```yaml
# application.yml
spring:
data:
mongodb:
uri: mongodb://username:password@localhost:27017/database_name
```
3. 创建实体类
创建一个实体类,用于映射MongoDB中的文档:
```java
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "blog_posts")
public class BlogPost {
@Id
private String id;
private String title;
private String content;
private Date createTime;
// 省略getter和setter方法
}
```
4. 创建Repository接口
创建一个继承自MongoRepository的接口,用于操作MongoDB集合:
```java
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.BlogPost;
@Repository
public interface BlogPostRepository extends MongoRepository
}
```
5. 在服务类中使用Repository接口
在服务类中,我们可以注入BlogPostRepository接口,并通过它来操作MongoDB集合:
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.entity.BlogPost;
import com.example.demo.repository.BlogPostRepository;
@Service
public class BlogPostService {
@Autowired
private BlogPostRepository blogPostRepository;
public BlogPost saveBlogPost(BlogPost blogPost) {
return blogPostRepository.save(blogPost);
}
}
```
至此,我们已经完成了Spring Boot与MongoDB的整合。接下来,我们将结合博客系统的访问记录,演示MongoTemplate的基本用法。