SpringBoot 整合 Mybatis Plus/MongoDB
将 Mybatis/MongoDB 集成到 SpringBoot 中的示例
前置要求
本文假设你已经了解或知道以下技能,尤其而且是勾选的内容。
- Gradle
- SpringBoot
- Mybatis Plus
- MongoDB
- SpringBoot MongoDB Data
- H2DB
- SpringTest
场景
需要同时使用 Mybatis-Plus
和 MongoDB
,所以就去了解了一下如何集成它们。
集成 Mybatis Plus
创建 SpringBoot 项目
使用 SpringIO 创建 SpringBoot 项目,初始依赖选择 web
, h2
两个模块,gradle 配置如下
1 | plugins { |
注:数据库吾辈这里为了简单起见直接使用了
H2DB
,真实项目中可能需要配置MySQL
之类。为了简化项目依赖配置文件,所以使用了 Gradle 而非 Maven。
引入 Mybatis-Plus 和 MongoDB 依赖
在 build.gradle
中引入 mybatis-plus-boot-starter
依赖
1 | dependencies { |
添加测试数据库
在 src/resources 下创建两个 sql 文件 schema-h2.sql
和 data-h2.sql
,简单的使用 H2DB
创建数据库/表并添加数据以供测试使用。
数据库结构:schema-h2.sql
1 | create schema spring_boot_mybatis_plus_mongo; |
数据库测试数据:data-h2.sql
1 | use spring_boot_mybatis_plus_mongo; |
配置 Mybatis Plus
在 application.yml
中添加数据源配置
1 | # DataSource Config |
添加一些实体/Dao/Service
用户信息实体类:com.rxliuli.example.springbootmybatisplusmongo.entity.UserInfo
1 |
|
用户信息 Dao:com.rxliuli.example.springbootmybatisplusmongo.dao.UserInfoDao
1 |
|
用户信息业务接口:com.rxliuli.example.springbootmybatisplusmongo.service.UserInfoService
1 | public interface UserInfoService extends IService<UserInfo> { |
用户信息业务接口实现类:com.rxliuli.example.springbootmybatisplusmongo.service.impl.UserInfoServiceImpl
1 |
|
配置 Mybatis Plus 扫描的路径
在启动类配置 Mybatis Plus
,这点非常重要,以致于吾辈要单独列出,可能会出现的问题参见 踩坑 部分
1 |
|
测试使用 Mybatis Plus 的 UserInfoService
测试 Mybatis Plus 中 IService
接口的 list()
方法
1 |
|
集成 MongoDB
引入 MongoDB Boot Starter
在 build.gradle
中引入 spring-boot-starter-data-mongodb
依赖
1 | dependencies { |
配置 MongoDB
在 application.yml
中添加 MongoDB 的配置,现在 application.yaml
应该变成了下面这样
1 | # DataSource Config |
添加 Repository
定义一些简单操作的 Dao 接口:com.rxliuli.example.springbootmybatisplusmongo.repository.UserInfoLogRepository
1 |
|
自定义更加复杂需求的 Dao 接口:com.rxliuli.example.springbootmybatisplusmongo.repository.CustomUserInfoLogRepository
1 | public interface CustomUserInfoLogRepository { |
具体的实现类:com.rxliuli.example.springbootmybatisplusmongo.repository.UserInfoLogRepositoryImpl
1 | /** |
配置 MongoDB 扫描的路径
修改启动类,添加 @EnableMongoRepositories
注解用以配置 MongoDB 扫描的 Repository
路径
1 |
|
测试使用 MongoDB 的 UserInfoLogRepository
- 测试
UserInfoLogRepository
中由 MongoDB Data 自动实现的findUserInfoLogByIdEquals()
方法 - 测试
CustomUserInfoLogRepository
中自定义复杂的listByParam()
方法
1 |
|
同时使用 Mybatis Dao 和 MongoDB Repository
在 Service 中添加方法
用户信息业务接口:com.rxliuli.example.springbootmybatisplusmongo.service.UserInfoService
1 | public interface UserInfoService extends IService<UserInfo> { |
用户信息业务接口实现类:com.rxliuli.example.springbootmybatisplusmongo.service.impl.UserInfoServiceImpl
1 |
|
添加简单的 RestAPI 进行测试
1 |
|
测试 RestAPI
现在,我们启动项目并打开浏览器,应当可以在以下地址看到对应的 JSON 数据
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14[
{
"id": 1,
"name": "rx",
"age": 17,
"sex": false
},
{
"id": 2,
"name": " 琉璃 ",
"age": 18,
"sex": false
}
] -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24{
"{\"id\":\"1\",\"name\":\"rx\",\"age\":17,\"sex\":false}": [
{
"id": 1,
"userId": 1,
"operate": " 登录 ",
"logTime": "2019-02-22T16:22:16.099"
},
{
"id": 2,
"userId": 1,
"operate": " 退出 ",
"logTime": "2019-02-22T16:22:16.099"
}
],
"{\"id\":\"2\",\"name\":\"琉璃 \",\"age\":18,\"sex\":false}": [
{
"id": 3,
"userId": 2,
"operate": " 登录 ",
"logTime": "2019-02-22T16:22:16.099"
}
]
}
踩坑
Mybatis Plus 扫包范围
使用@MapperScan
限制 Mybatis Plus 扫描Dao
的范围,注意不要扫到 MongoDB 的Repository
,否则会抛出异常1
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'userInfoLogRepository' defined in null: Cannot register bean definition [Root bean: class [org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] for bean 'userInfoLogRepository': There is already [Generic bean: class [org.mybatis.spring.mapper.MapperFactoryBean]; scope=singleton; abstract=false; lazyInit=false; autowireMode=2; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\Text\spring-boot\spring-boot-mybatis-plus-mongo\out\production\classes\com\rxliuli\example\springbootmybatisplusmongo\repository\UserInfoLogRepository.class]] bound.
原因是在 SpringMongoData 处理之前 Mybatis Plus 先扫描到并进行了代理,然后就会告诉你无法注册 SpringMongoData 相关的
Repository
使用
@EnableMongoRepositories
限制 SpringMongoData 扫描的范围既然说到限制,自然也不得不说一下 SpringMongoData 本身,如果你已经使用了
@MapperScan
扫描 Mybatis 需要处理的 Dao,那么添加与否并不重要。但是,吾辈要说但是了,但是,如果你先使用的 MongoDB,那么如果没有使用@MapperScan
处理 Mybatis 的 Dao 的话,就会抛出以下异常,所以为了安全起见还是都定义了吧1
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userInfoServiceImpl': Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.rxliuli.example.springbootmybatisplusmongo.dao.UserInfoDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: { .springframework.beans.factory.annotation.Autowired(required=true)}
说的是自动注入
BaseMapper
失败,实际上是因为 Mybatis 的 Dao SpringMongoData 无法处理。最好使用不同的后缀名区分
Mybatis Mapper
和Mongo Repository
,或者放到不同的包
也是为了避免扫描混乱,出现Mybatis
扫描到Mongo Repository
或是Mongo
扫描到Mybatis Mapper
的情况,出现上面的那两个错误。
那么,关于在 SpringBoot 中同时使用 Mybatis Plus 和 MongoDB 的搭建就到这里啦