引入依赖
springboot集成MongoDb引入依赖
<!--spring data mongodb--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
看一下MongoRepository接口,它集成了 spring-data-commons的PagingAndSortingRepository接口和QueryByExampleExecutor接口
public interface MongoRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
spring-data包介绍
Spring Data 是spring的组件之一,主要目的是为了让开发者再工作中能更加轻松的完成CURD,简化代码应该是所有框架的目的吧。Spring-data-commons只是其中的一个模块而已,spring-data-mongo包含了spring-data-comons,另外spring-data-JPA也是实现了spring-data-common的接口完成简单的CRUD操作以及复杂自定义的查询更新操作。
JPA操作手册:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
最底层的接口是:
package org.springframework.data.repository;@Indexed public interface Repository<T, ID> { }中央存储库标记接口,通过实现这个接口进行扩展查询比如分页,排序等操作
jpa自定义查询的一些规范
查询创建
通常,JPA 的查询创建机制如“查询方法”中所述。以下示例显示了 JPA 查询方法转换为的内容:
公共接口 UserRepository 扩展 Repository<User, Long> {
List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
关键词 | 样本 | JPQL 片段 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MongoRepository使用
自定义实体类:
@Data @Builder @AllArgsConstructor @NoArgsConstructor public class User implements Serializable { @Id private String id; private String userName; private String userId; private Integer age; private String sex; @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss") private Date birthDay; }
定义Dao层操作MongoDB
@Repository public interface UserRepository extends MongoRepository<User,String> { List<User> findByUserNameLike(String userName); }
service层
public interface UserService { /** * 模糊查询 * @param userName 用户名 * @return List */ List<User> findUserName(String userName); /** * 保存用户信息 * @param user user用户信息 */ void saveUser(User user); /** * 根据用户id删除用户 * @param userId 用户Id */ void deleteUser(String userId); /** * @param pageable 分页信息 * @return Page */ Page<User> findUserPage(Pageable pageable); /** * 更新用户信息 * @param user 用户信息 */ void updateUserInfo(User user); /** * 模糊查询 按照名字 * @param userName * @return List */ List<User> findLikeUserName(String userName); /** * 查询所有数据 * @return List */ List<User> findAll(); }
controller层:
@Slf4j @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/find/userName") public CommonResponse findUserName(@RequestParam("userName") String userName) { List<User> users = userService.findUserName(userName); return CommonResponse.success(users); } @GetMapping("/find/like") public CommonResponse findLikeUserName(@RequestParam("userName") String userName) { List<User> users = userService.findLikeUserName(userName); return CommonResponse.success(users); } @PostMapping("/save") public CommonResponse save(@RequestBody User user) { userService.saveUser(user); return CommonResponse.success(); } @PutMapping("/update") public CommonResponse update(@RequestBody User user) { userService.updateUserInfo(user); return CommonResponse.success(); } @GetMapping("/page") public CommonResponse page(@RequestParam Integer page, @RequestParam Integer limit) { MongoPageAble mongoPageAble = MongoPageAble.of(page, limit); Page<User> page1 = userService.findUserPage(mongoPageAble); return CommonResponse.success(new PageInfoDTO<>(page1)); } @DeleteMapping("/delete") public CommonResponse delete(@RequestParam String userId) { userService.deleteUser(userId); return CommonResponse.success(); } @GetMapping("/find/all") public CommonResponse findAll() { List<User> users = userService.findAll(); return CommonResponse.success(users); } }
提供自定义的分页查询数据PO:
public class MongoPageAble extends AbstractPageRequest { private Sort sort; public MongoPageAble(int pageNum, int pageSize, Sort sort) { super(pageNum, pageSize); this.sort = sort; } public static MongoPageAble of(int page, int size) { return of(page, size, Sort.unsorted()); } public static MongoPageAble of(int page, int size, Sort sort) { return new MongoPageAble(page, size, sort); } public static MongoPageAble of(int page, int size, Sort.Direction direction, String... properties) { return of(page, size, Sort.by(direction, properties)); } @Override public Sort getSort() { return sort; } @Override public Pageable next() { return new MongoPageAble(this.getPageNumber() + 1, this.getPageSize(), this.getSort()); } @Override public Pageable previousOrFirst() { return this.hasPrevious() ? this.previous() : this.first(); } @Override public Pageable previous() { return this.getPageNumber() == 1 ? this : new MongoPageAble(this.getPageNumber() - 1, this.getPageSize(), this.getSort()); } @Override public Pageable first() { return new MongoPageAble(1, this.getPageSize(), this.getSort()); } public void setSort(Sort sort) { this.sort = sort; } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } else if (!(obj instanceof MongoPageAble)) { return false; } else { MongoPageAble that = (MongoPageAble)obj; return super.equals(that) && this.sort.equals(that.sort); } } @Override public int hashCode() { return 31 * super.hashCode() + this.sort.hashCode(); } @Override public String toString() { return String.format("Page request [number: %d, size %d, sort: %s]", this.getPageNumber(), this.getPageSize(), this.sort); } /** * 使用分页这个一定要改写 他们默认的分页是以下标0开始 * @return */ @Override public long getOffset() { return ( (getPageNumber()-1) * getPageSize()); } }
其中需要注意的是getOffset方法,因为mongoDB在实际执行分页查询时候,走的是skip().limit()操作,skip表示跳过查询的数量,这里传入的参数offset偏移量,而我们接口实际查询的时候页数page是从1开始的,mongo在计算偏移量的时候是offset=page*size 导致跳过第一页数据
自定义封装分页查询结果:
@Data @NoArgsConstructor public class PageInfoDTO<T> { /** * 总记录数 */ private Integer totalCount; /** * 每页记录数 */ private Integer pageSize; /** * 总页数 */ private Integer totalPage; /** * 开始页数默认从1 */ private Integer startPage; /** * 列表数据 */ private List<T> list; /** * 分页 * * @param list 列表数据 * @param pageSize 每页记录数 * @param startPage 当前页数 */ public PageInfoDTO(List<T> list, Integer pageSize, Integer startPage) { this.list = list; this.totalCount = list.size(); this.pageSize = pageSize; this.startPage = startPage; this.totalPage = (int) Math.ceil((double) totalCount / pageSize); } /** * 分页 */ public PageInfoDTO(IPage<T> page) { this.list = page.getRecords(); this.totalCount = (int) page.getTotal(); this.pageSize = (int) page.getSize(); this.startPage = (int) page.getCurrent(); this.totalPage = (int) page.getPages(); } public PageInfoDTO(Page<T> page) { // this.list = page.get().collect(Collectors.toList()); this.list = page.getContent(); this.totalCount = (int) page.getTotalElements(); this.pageSize = page.getSize(); this.startPage = page.getPageable().getPageNumber(); this.totalPage = page.getTotalPages(); } }
下面开始实际测试:
插入数据:
查询全部数据:
查询结果:
{
"success": true,
"code": "200",
"msg": "操作成功",
"data": [
{
"id": "1111",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "男",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "222",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "男",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "333",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "男",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "444",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "555",
"userName": "小王22",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "666",
"userName": "小王11",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
}
]
}
模糊查询:
查询结果:
{
"success": true,
"code": "200",
"msg": "操作成功",
"data": [
{
"id": "1111",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "男",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "222",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "男",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "333",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "男",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "444",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "555",
"userName": "小王22",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "666",
"userName": "小王11",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
}
]
}
分页查询:
localhost:8080/user/page?page=2&limit=3
查询结果:
{
"success": true,
"code": "200",
"msg": "操作成功",
"data": {
"totalCount": 6,
"pageSize": 3,
"totalPage": 2,
"startPage": 2,
"list": [
{
"id": "444",
"userName": "小王",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "555",
"userName": "小王22",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
},
{
"id": "666",
"userName": "小王11",
"userId": "23",
"age": 23,
"sex": "女",
"birthDay": "2020-11-20 20:02:20"
}
]
}
}
在实际开发中也可使用MongoTemplate代替上面的操作 ,后续会介绍MongoTemplate的CRUD操作以及分页聚合排序等