创建工程
在spring-boot-nosql下创建spring-boot-nosql-mongodb工程
启动类:
com.mirson.db.startup.NosqlMongodbApplication:
@SpringBootApplication
@ComponentScan(basePackages = {"com.mirson"})
@EnableMongoRepositories(basePackages = "com.mirson")
public class NosqlMongodbApplication {public static void main(String[] args) {SpringApplication.run(NosqlMongodbApplication.class, args);}}
注意, 要使用MongoRepository功能, 需要开启EnableMongoRepositories注解, 扫描Repository接口。
MAVEN依赖
<dependencies><!-- MongoDB 依赖组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!-- MongoDB Reactive 依赖组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb-reactive</artifactId></dependency><!-- Json 转换组件 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency></dependencies>
这里需要用到JSON作参数数据转换, 引入fastjson组件。
工程配置
单节点模式配置
server:port: 11613
spring:application:name: nosql-mongodb# MongoDB 缓存配置data:mongodb:# 主机host: 127.0.0.1# 端口port: 27017# 连接数据库database: mongo-samples
单节点配置, 定义主机地址、端口和数据库名称即可。
集群模式配置
server:port: 11613
spring:application:name: nosql-mongodb# MongoDB 缓存配置data:mongodb:# 集群连接配置uri: mongodb://127.0.0.1:27011,127.0.0.1:27012,127.0.0.1:27013/mongo-samples
集群模式配置, 将所有节点地址和端口及数据库名称统一放在uri里面, 注意多个节点以逗号分割 ;
如果有密码认证, 把认证信息放在地址前面, 例:
uri: mongodb://username:password@127.0.0.1:27011,127.0.0.1:27012,127.0.0.1:27013/mongo-samples
Spring Boot 封装的MongoDB, 没有提供连接池配置, 如果需要实现连接池, 可以自行封装替换内置的MongoDbFactory。
创建实体
com.mirson.ity.Person:
@Document(collection="person")
@Data
public class Person implements Serializable {private static final long serialVersionUID = -1L;@Idprivate String id;/*** 姓名*/@Indexed(unique=true)private String name;/*** 年龄*/private Integer age;/*** 省份*/private String province;/*** 创建时间*/@CreatedDateDate createDate;}
定义CURD等接口
接口定义
com.mirson.db.service.IMongoService
public interface IMongoService {/*** 保存用户信息* @param person*/public String save(Person person);/*** 删除用户* @param id*/public void delete(String id);/*** 查询所有用户*/public List<Person> find(String id);/*** 根据名称模糊查找* @param name* @return*/public List<Person> findByName(String name);/*** 批量保存数据* @param personList* @return*/public String batchSave(String opt, List<Person> personList);}
覆盖常用的功能接口, 包括模糊匹配, 批量数据保存。
接口实现
com.mirson.db.service.MongoTemplateServiceImpl
@Service
@Log4j2
public class MongoTemplateServiceImpl implements IMongoService {@Autowiredprivate MongoTemplate mongoTemplate;/*** 保存对象* @param person* @return*/@Overridepublic String save(Person person) {log.info("save person: " + person);Person result = mongoTemplate.save(person);Id();}/*** 根据ID删除对象* @param id*/@Overridepublic void delete(String id) {log.info("delete person: " + id);Query query = new Query(Criteria.where("id").is(id));ve(query, Person.class);}/*** 根据ID查找对象* @param id* @return*/@Overridepublic List<Person> find(String id) {log.info(" find person: " + id);if(StringUtils.isEmpty(id)){// 为空, 查找所有对象return mongoTemplate.findAll(Person.class);}// 查找指定对象Query query = new Query(Criteria.where("id").is(id));return mongoTemplate.find(query, Person.class);}/*** 根据名称查找对象, 支持模糊匹配* @param name* @return*/@Overridepublic List<Person> findByName(String name) {log.info(" findByName, name: " + name);Query query = new Query(Criteria.where("name").regex(name));return mongoTemplate.find(query, Person.class);}/*** 批量保存数据* @param personList* @return*/@Transactional(rollbackFor = Exception.class)public String batchSave(String opt, List<Person> personList) {log.info("batchSave, personList: " + personList);if(null != personList && !personList.isEmpty()) {// 遍历对象集合for (int i= 0; i< personList.size(); i++) {if(i == 1 && "exception".equals(opt)) {// 手工触发异常, 验证事务有效性throw new RuntimeException("throw manual exception!");}// 保存对象mongoTemplate.(i));}return "batch save success.";}return "empty data.";}}
根据ID查找对象, 如果ID为空, 则查询获取所有对象数据。
根据名称查找对象, 支持模糊匹配, 通过regex接口实现, 可以支持更灵活的匹配:
//完全匹配
Pattern pattern = Patternpile("^用户$", Pattern.CASE_INSENSITIVE);
//右匹配
Pattern pattern = Patternpile("^.*用户$", Pattern.CASE_INSENSITIVE);
//左匹配
Pattern pattern = Patternpile("^用户.*$", Pattern.CASE_INSENSITIVE);
//模糊匹配
Pattern pattern = Patternpile("^.*用户.*$", Pattern.CASE_INSENSITIVE);
Query query = Query.query(Criteria.where(fieldName).regex(pattern));
batchSave 批量保存数据, 用到事务, 在MongoTransactionManager事务的使用章节再进行讲解。
提供Web层调用接口
因为有几种不同模式的集成使用, 都提供相同的调用接口, 我们把它们做个封装, 不重复编写。
定义抽象类com.mirson.ller.AbstractController
public abstract class AbstractController {/*** MongoDB接口操作实现类* @return*/public abstract IMongoService getMongoService();/*** 保存用户* @param person* @return*/@GetMapping("/save")public String save(Person person) {String id = getMongoService().save(person);return "save success. id: " + id;}/*** 删除用户* @param id* @return*/@GetMapping("/delete")public String delete(String id) {getMongoService().delete(id);return "delete success.";}/*** 查找用户* @param id* @return*/@GetMapping("/find")@ResponseBodypublic List<Person> find(String id) {List<Person> personList = getMongoService().find(id);return personList;}/*** 根据名称查找, 支持模糊匹配* @param name* @return*/@GetMapping("/findByName")@ResponseBodypublic List<Person> findByName(String name) {List<Person> personList = getMongoService().findByName(name);return personList;}/*** 批量保存, 事务验证* @param opt* @param personJson* @return*/@PostMapping("/batchSave")@ResponseBodypublic String batchSave(String opt, String json) {List<Person> personList = JSON.parseArray(json,Person.class);return getMongoService().batchSave(opt, personList);}}
将服务层的接口,提供对外访问调用, 因为所有服务层实现IMongoService接口, 在不同模式下提供getMongoService()方法的具体实现即可。这里父类定义好各接口的访问路径, 子类中再定义@RequestMapping加以前缀识别。
com.mirson.ller.MongoTemplateController:
@RestController
@RequestMapping("/template")
@Log4j2
public class MongoTemplateController extends AbstractController{@Autowiredprivate IMongoService mongoTemplateServiceImpl;@Overridepublic IMongoService getMongoService() {return mongoTemplateServiceImpl;}
}
MongoTemplateController注入mongoTemplateServiceImpl, 实现getMongoService方法。
RequestMapping定义访问路径要加上/template。
验证
测试新增功能
新增一个名为user1, 年龄为21, 省份为江西省的记录
URL: /template/save?name=user1&age=21&province=江西省
保存成功, 返回ID: 5d7791f55c72e7242ce8ded8
测试更新功能
调用保存接口, 当传入参数包含ID时, 会自动更新对应记录。
将年龄由21改为31
更新成功, 查看compass中数据是否一致:
修改成功。
测试删除功能
将刚才创建的数据删除, 传入ID参数: 5d7791f55c72e7242ce8ded8
成功删除。
测试查询功能
通过上面测试方法, 重新创建数据, 创建新数据的时候不要指定ID参数。
指定ID查询记录:
URL: /template/find?id=5d7793c45c72e7242ce8deda
不传递ID, 查询所有记录:
URL: /template/find
测试模糊查询
检索所有名称为user的记录
URL: /template/findByName?name=user
检索所有名称为test的记录, 没有新增此类数据, 查询应为空
定义JPA接口
com.mirson.pository.IPersonMongoDao
@Repository
public interface IPersonMongoDao extends MongoRepository<Person, String> {/*** 根据ID获取对象* @param id* @return*/Optional<Person> findById(String id);/*** 根据名称模糊搜索* @param name* @param pageable* @return*/Page<Person> findByNameLike(String name, Pageable pageable);/*** 获取所有对象* @param pageable* @return*/Page<Person> findAll(Pageable pageable);}
findByNameLike方法, 提供了模糊搜索支持和分页功能, 这些都是JPA内置帮我们实现, 更多用法:
Keyword | Sample | Logical result |
---|---|---|
After | findByBirthdateAfter(Date date) | {"birthdate" : {"$gt" : date}} |
GreaterThan | findByAgeGreaterThan(int age) | {"age" : {"$gt" : age}} |
GreaterThanEqual | findByAgeGreaterThanEqual(int age) | {"age" : {"$gte" : age}} |
Before | findByBirthdateBefore(Date date) | {"birthdate" : {"$lt" : date}} |
LessThan | findByAgeLessThan(int age) | {"age" : {"$lt" : age}} |
LessThanEqual | findByAgeLessThanEqual(int age) | {"age" : {"$lte" : age}} |
Between | findByAgeBetween(int from, int to) | {"age" : {"$gt" : from, "$lt" : to}} |
In | findByAgeIn(Collection ages) | {"age" : {"$in" : [ages…]}} |
NotIn | findByAgeNotIn(Collection ages) | {"age" : {"$nin" : [ages…]}} |
IsNotNull , NotNull | findByFirstnameNotNull() | {"firstname" : {"$ne" : null}} |
IsNull , Null | findByFirstnameNull() | {"firstname" : null} |
Like , StartingWith , EndingWith | findByFirstnameLike(String name) | {"firstname" : name} (name as regex) |
NotLike , IsNotLike | findByFirstnameNotLike(String name) | {"firstname" : { "$not" : name }} (name as regex) |
Containing on String | findByFirstnameContaining(String name) | {"firstname" : name} (name as regex) |
NotContaining on String | findByFirstnameNotContaining(String name) | {"firstname" : { "$not" : name}} (name as regex) |
Containing on Collection | findByAddressesContaining(Address address) | {"addresses" : { "$in" : address}} |
NotContaining on Collection | findByAddressesNotContaining(Address address) | {"addresses" : { "$not" : { "$in" : address}}} |
Regex | findByFirstnameRegex(String firstname) | {"firstname" : {"$regex" : firstname }} |
(No keyword) | findByFirstname(String name) | {"firstname" : name} |
Not | findByFirstnameNot(String name) | {"firstname" : {"$ne" : name}} |
Near | findByLocationNear(Point point) | {"location" : {"$near" : [x,y]}} |
Near | findByLocationNear(Point point, Distance max) | {"location" : {"$near" : [x,y], "$maxDistance" : max}} |
Near | findByLocationNear(Point point, Distance min, Distance max) | {"location" : {"$near" : [x,y], "$minDistance" : min, "$maxDistance" : max}} |
Within | findByLocationWithin(Circle circle) | {"location" : {"$geoWithin" : {"$center" : [ [x, y], distance]}}} |
Within | findByLocationWithin(Box box) | {"location" : {"$geoWithin" : {"$box" : [ [x1, y1], x2, y2]}}} |
IsTrue , True | findByActiveIsTrue() | {"active" : true} |
IsFalse , False | findByActiveIsFalse() | {"active" : false} |
Exists | findByLocationExists(boolean exists) | {"location" : {"$exists" : exists }} |
MongoDBRepository所提供的不同功能的操作接口:
Repository
: 仅仅是一个标识,表明任何继承它的均为仓库接口类
CrudRepository
: 继承 Repository,实现了一组 CRUD 相关的方法
PagingAndSortingRepository
: 继承 CrudRepository,实现了一组分页排序相关的方法
MongoRepository
: 继承 PagingAndSortingRepository,实现一组 mongodb规范相关的方法
定义Service实现类
com.mirson.db.service.MongoRepositoryServiceImpl
@Service
@Log4j2
public class MongoRepositoryServiceImpl implements IMongoService{@Autowiredprivate IPersonMongoDao personMongoDao;/*** 保存对象* @param person* @return*/@Overridepublic String save(Person person) {log.info("repository save person: " + person);Person result = personMongoDao.save(person);Id();}/*** 根据ID删除对象* @param id*/@Overridepublic void delete(String id) {personMongoDao.deleteById(id);log.info("repository delete person, id: " + id);}/*** 根据ID查找对象* @param id* @return*/@Overridepublic List<Person> find(String id) {log.info("repository find person, id: " + id);if(!StringUtils.isEmpty(id)) {// 根据ID查询Optional<Person> personOptional = personMongoDao.findById(id);if(personOptional.isPresent()) {return Arrays.());}}else {// 获取所有对象, 支持分页查询Pageable pageable = new PageRequest(0, 100);Page<Person> personPage = personMongoDao.findAll(pageable);Content();}return null;}/*** 根据名称查找对象, 支持模糊匹配* @param name* @return*/@Overridepublic List<Person> findByName(String name) {log.info("repository findByName, name: " + name);Pageable pageable = new PageRequest(0, 100);Page<Person> personPage = personMongoDao.findByNameLike(name, pageable);Content();}/*** 批量保存数据* @param personList* @return*/@Transactional(rollbackFor = Exception.class)public String batchSave(String opt, List<Person> personList) {log.info("repository batchSave, personList: " + personList);if(null != personList && !personList.isEmpty()) {// 遍历对象集合for (int i= 0; i< personList.size(); i++) {if(i == 1 && "exception".equals(opt)) {// 手工触发异常, 验证事务有效性throw new RuntimeException("throw manual exception!");}// 保存对象personMongoDao.(i));}return "batch save success.";}return "empty data.";}}
根据名称模糊搜索, 调用内置的LIKE接口, 帮我们封装实现了与LIKE类似的模糊匹配功能, 这里加上Pageable参数, 是演示Pageable的用法, 实际工作中, 会对分页的计算做进一步封装, 这里不作详解。
定义Web层访问接口
com.mirson.ller.MongoRepositoryController
@RestController
@RequestMapping("/repository")
public class MongoRepositoryController extends AbstractController{@Autowiredprivate IMongoService mongoRepositoryServiceImpl;@Overridepublic IMongoService getMongoService() {return mongoRepositoryServiceImpl;}}
注入类的名称为mongoRepositoryServiceImpl, 不能写错, 因为有多个实现类, 调用时可以观察日志检查处理类有无配置错误。
功能验证
保存功能
控制台日志, 正确进入Repository模式处理:
删除功能
查询功能
模糊查询
JAVA CONFIG配置
使用MongoDB需要开启MongoTransactionManager事务管理器, 默认Spring Boot是不会加载注入。
com.mirson.fig.MongodbConfiguration:
@Configuration
@EnableMongoAuditing
public class MongodbConfiguration {/*** Transaction MongoDB 事务配置* @param dbFactory* @return*/@BeanMongoTransactionManager transactionManager(MongoDbFactory dbFactory) {return new MongoTransactionManager(dbFactory);}}
创建MongoTransactionManager, 纳入容器管理。
Service层实现
前面我们定义了batchSave方法, 这里我们把Template和Repository两种模式都实现事务测试接口进行验证。
batchSave方法是批量保存用户数据, 事务验证需要模拟一个异常, 触发事务的回滚, 这里通过opt参数来控制, 如果传递值为"exception", 则手动抛出异常, 触发事务回滚机制。
Template模式实现类修改
MongoTemplateServiceImpl:
/*** 批量保存数据* @param personList* @return*/@Transactional(rollbackFor = Exception.class)public String batchSave(String opt, List<Person> personList) {log.info("batchSave, personList: " + personList);if(null != personList && !personList.isEmpty()) {// 遍历对象集合for (int i= 0; i< personList.size(); i++) {if(i == 1 && "exception".equals(opt)) {// 手工触发异常, 验证事务有效性throw new RuntimeException("throw manual exception!");}// 保存对象mongoTemplate.(i));}return "batch save success.";}return "empty data.";}
Repository模式实现类修改
MongoRepositoryServiceImpl
/*** 批量保存数据* @param personList* @return*/@Transactional(rollbackFor = Exception.class)public String batchSave(String opt, List<Person> personList) {log.info("repository batchSave, personList: " + personList);if(null != personList && !personList.isEmpty()) {// 遍历对象集合for (int i= 0; i< personList.size(); i++) {if(i == 1 && "exception".equals(opt)) {// 手工触发异常, 验证事务有效性throw new RuntimeException("throw manual exception!");}// 保存对象personMongoDao.(i));}return "batch save success.";}return "empty data.";}
WEB层接口
AbstractController
/*** 批量保存, 事务验证* @param opt* @param personJson* @return*/@PostMapping("/batchSave")@ResponseBodypublic String batchSave(String opt, String json) {List<Person> personList = JSON.parseArray(json,Person.class);return getMongoService().batchSave(opt, personList);}
提供两个参数opt, 用于控制是否抛出异常; 另一个json参数是以JSON格式传递多个Person对象, 通过fastjson组件将json字符串转换为对象。
事务功能验证
为便于演示, 先清除所有数据
如果数据过多, 可以通过Compass工具,直接将数据库删除, 程序重新启动会自动创建数据库和表。
Template模式,验证批量保存(不抛出异常)
查询数据:
Template模式,先清除所有测试数据, 验证批量保存(模拟抛出异常)
查询数据:
Repository模式, 验证批量保存(不抛出异常, 测试前清除所有数据)
查询数据:
Repository模式,验证批量保存(模拟抛出异常)。
查询数据:
定义Service层接口
com.mirson.db.service.MongoReactiveServiceImpl
@Service
@Log4j2
public class MongoReactiveServiceImpl implements IMongoService {@Autowiredprivate ReactiveMongoTemplate reactiveMongoTemplate;/*** 保存对象* @param person* @return*/@Overridepublic String save(Person person) {Mono<Person> result = reactiveMongoTemplate.save(person);result.subscribe(log::info);log.info("Reactive save person: " + person);return result.block().getId();}/*** 根据ID删除对象* @param id*/@Overridepublic void delete(String id) {Query query = new Query(Criteria.where("id").is(id));Mono<DeleteResult> result = ve(query, Person.class);result.subscribe(log::info);log.info("Reactive delete person: " + id);}/*** 根据ID查找对象* @param id* @return*/@Overridepublic List<Person> find(String id) {log.info("Reactive find person: " + id);if(StringUtils.isEmpty(id)){// 为空, 查找所有对象Flux<Person> result = reactiveMongoTemplate.findAll(Person.class);llectList().block();}// 查找指定对象Query query = new Query(Criteria.where("id").is(id));Flux<Person> result = reactiveMongoTemplate.find(query, Person.class);llectList().block();}/*** 根据名称查找对象, 支持模糊匹配* @param name* @return*/@Overridepublic List<Person> findByName(String name) {log.info("Reactive findByName, name: " + name);Query query = new Query(Criteria.where("name").regex(name));Flux<Person> result = reactiveMongoTemplate.find(query, Person.class);llectList().block();}/*** 批量保存数据* @param personList* @return*/@Transactional(rollbackFor = Exception.class)public String batchSave(String opt, List<Person> personList) {log.info("Reactive batchSave, personList: " + personList);if(null != personList && !personList.isEmpty()) {// 遍历对象集合for (int i= 0; i< personList.size(); i++) {if(i == 1 && "exception".equals(opt)) {// 手工触发异常, 验证事务有效性throw new RuntimeException("throw manual exception!");}// 保存对象Mono<Person> result = reactiveMongoTemplate.(i));result.block();}return "Reactive batch save success.";}return "Reactive empty data.";}}
使用Reactive模式, 确保加入spring-boot-starter-data-mongodb-reactive依赖, 该组件会自动装配ReactiveMongoTemplate。Reactive支持阻塞和异步调用, 通过日志打印可以看出其异步特性。
定义WEB层接口
com.mirson.ller.MongoReactiveController
@RestController
@RequestMapping("/reactive")
public class MongoReactiveController extends AbstractController {@Autowiredprivate IMongoService mongoReactiveServiceImpl;@Overridepublic IMongoService getMongoService() {return mongoReactiveServiceImpl;}}
继承AbstractController所提供的接口, 定义RequestMapping路径为“/reactive”。
验证
保存数据
删除数据
查询数据
模糊查询
异步操作日志
通过刚才调用删除接口的日志打印, 可以看出为Reactive的异步操作特性。
本文发布于:2024-01-29 05:19:49,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170647679412978.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |