Spring boot集成mongoDB使用MongoRepository

引入依赖

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 查询方法转换为的内容:

示例 57. 从方法名称创建查询
公共接口 UserRepository 扩展 Repository<User, Long> {

  List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}

表 3. 方法名称中支持的关键字
关键词样本JPQL 片段

Distinct

findDistinctByLastnameAndFirstname

select distinct …​ where x.lastname = ?1 and x.firstname = ?2

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstnamefindByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull,Null

findByAge(Is)Null

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1(与 append 绑定的参数%

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(以 prepended 绑定的参数%

Containing

findByFirstnameContaining

… where x.firstname like ?1(参数绑定在 中%

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstname) = UPPER(?1)

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();
    }
}

 下面开始实际测试:

插入数据:

查询全部数据:

http://localhost:8080/user/find/all

 查询结果:

{

    "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"

        }

    ]

}

模糊查询:

http://localhost:8080/user/find/like?userName=小王

 查询结果:

{

    "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操作以及分页聚合排序等

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员路同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值