文章目录
MyBatis Plus 是一款基于 MyBatis 的国产开源框架,它能够简化 MyBatis 的开发,类似于 Spring Data Jpa,都是全自动化的 ORM 框架,其中封装了单表的 curd 操作。同时,当需要完成多表操作时,也可以使用 MyBatis 去手动实现。最后,通过 Spring Boot + MyBatis-Plus,我们还可以快速生成 eneity、mapper、service、controller 层的代码,十分方便。
- 以下是 Spring Boot 整合 MyBatis-Plus 快速搭建 Java 后端环境的步骤,适用于快速开发。
一、MyBatis-Plus 环境搭建
1、导入 MyBatis-Plus 依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
注意点:导入 MyBatis-Plus 的依赖后,也可以直接使用 MyBatis。
2、配置文件
application.yml 如下:
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/curdtest?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
type-aliases-package: com.study.pojo
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package
: 指定开启别名映射的包名mapper-locations
: 指定mapper
文件的位置configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
: 在控制台打印 sql 日志
3、实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "user")
public class User {
@TableId
private Integer id;
@TableField(value = "name")
private String username;
private Integer age;
@TableField(select = false)
private Integer gender;
@TableField(exist = false)
private String address;
}
相关注解说明:
注解 | 说明 |
---|---|
@TableName | 映射数据库表名,当实体类名与数据库表名不一致时使用 |
@TableId | 必要,设置主键映射,一般需指定 type 为 AUTO 自增 |
@TableField | 映射非主键字段,exist = false 表示数据库中无该字段,select = false 表示不查询该字段 |
4、数据库访问层
创建 Mapper,添加 @Repository
与 @Mapper
注解,并继承 BaseMapper
:
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
以下是 BaseMapper
的源码,其中封装了大量的单表操作,MyBatis-Plus
与 Spring Data Jpa
都是全自动的 ORM
的框架,我们可以直接使用其中的 CURD
方法而无需手动实现:
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
二、单表查询(自动实现)
当需要指定查询条件时,一般需通过 QueryWrapper
对象的相应方法。
单表查询所有数据:
userMapper.selectList(null).forEach(System.out::println);
等值查询( eq:name = " 张三" ):
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("name","张三");
userMapper.selectList(wrapper).forEach(System.out::println);
多个条件时,可以用 Map 进行封装,再传入 QueryWrapper 中,此时使用 allEq :
QueryWrapper wrapper = new QueryWrapper();
Map<String, Object> map = new HashMap<>();
map.put("name", "张三");
map.put("age", "10");
wrapper.allEq(map);
userMapper.selectList(wrapper).forEach(System.out::println);
大于 gt(大于等于 ge):
QueryWrapper wrapper = new QueryWrapper();
wrapper.gt("age",15);
userMapper.selectList(wrapper).forEach(System.out::println);
不等于 ne:
QueryWrapper wrapper = new QueryWrapper();
wrapper.ne("name","张三");
userMapper.selectList(wrapper).forEach(System.out::println);
模糊查询:
QueryWrapper wrapper = new QueryWrapper();
wrapper.like("name","小");
userMapper.selectList(wrapper).forEach(System.out::println);
排序:
QueryWrapper wrapper = new QueryWrapper();
wrapper.orderByDesc("age");
userMapper.selectList(wrapper).forEach(System.out::println);
having:
QueryWrapper wrapper = new QueryWrapper();
wrapper.orderByDesc("age");
wrapper.having("id>2");
userMapper.selectList(wrapper).forEach(System.out::println);
selectById 根据主键查询:
System.out.println(userMapper.selectById(1));
selectBatchIds 查询集合里的所有记录:
userMapper.selectBatchIds(Arrays.asList(1,2,3)).forEach(System.out::println);
selectByMap 使用 Map 做等值判断:
Map<String,Object> map = new HashMap<>();
map.put("name","张三");
userMapper.selectByMap(map).forEach(System.out::println);
selectCount 统计个数:
QueryWrapper wrapper = new QueryWrapper();
wrapper.ge("age",12);
System.out.println(userMapper.selectCount(wrapper));
将查询结果封装到 Map 中:
QueryWrapper wrapper = new QueryWrapper();
wrapper.ge("age",12);
System.out.println(userMapper.selectMaps(wrapper));
分页查询
创建 MyBatisPlus 的配置类:
@Configuration
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
return paginationInterceptor;
}
}
必须要配置以上代码,否则无法生效
查询第 1 页,大小为 2 的记录:
Page<User> page = new Page<>(1,2);
Page<User> result = userMapper.selectPage(page, null);
System.out.println(result.getSize());
System.out.println(result.getTotal());
result.getRecords().forEach(System.out::println);
size 表示每页大小,total 表示总记录数
也可以用 Map 封装结果:
Page<Map<String, Object>> page = new Page<>(1, 2);
Page<Map<String, Object>> result = userMapper.selectMapsPage(page, null);
result.getRecords().forEach(System.out::println);
三、多表查询(自定义 sql )
以上操作只适用于单表查询,多表查询还是需要自己实现
新增一个 Article 表,创建对应的实体:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Article {
@TableId(type = IdType.AUTO)
private Integer aId;
private String title;
private Integer uId;
}
多表查询依旧可以使用 MyBatis,注意需在配置文件中添加 mapper-locations
的配置:
mybatis-plus:
type-aliases-package: com.study.pojo
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
在 Mapper 中自定义查询方法,在 xml 中写我们的 sql 即可:
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
User queryUserAndArticle(@Param("id") int id);
}
<select id="queryUserAndArticle" resultMap="userArticle">
select *
from user u, article a
where u.id = a.u_id and u.id = #{id};
</select>
<resultMap id="userArticle" type="user">
<result column="id" property="id"/>
<result column="name" property="username"/>
<result column="age" property="age"/>
<collection property="articles" ofType="article">
<result column="a_id" property="aId"/>
<result column="title" property="title"/>
</collection>
</resultMap>
上方是一对多的多表查询,通过 resultMap
返回。
多表联合查询的还有一种实现方式是:我们通过 VO(View Object)
对两个实体的信息进行组合,通过 sql 将属性映射到 VO 类中:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserArticleVO {
private Integer id;
private String name;
private Integer age;
private Integer aId;
private String title;
}
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
User queryUserAndArticle(@Param("id") int id);
List<UserArticleVO> queryVO(@Param("id") int id);
}
<select id="queryVO" resultType="com.study.vo.UserArticleVO">
select *
from user u, article a
where u.id = a.u_id and u.id = #{id};
</select>
得到相同的结果:
四、增、删、改
1、增加
User user = new User();
user.setUsername("小明");
user.setAge(12);
user.setGender(1);
userMapper.insert(user);
2、修改
User user = userMapper.selectById(4);
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("id",4);
user.setUsername("小明222");
user.setAge(12);
user.setGender(1);
userMapper.update(user,wrapper);
3、删除
根据主键删除:
userMapper.deleteById(4);
批量删除:
userMapper.deleteBatchIds(Arrays.asList(2,3)); // 批量删除
根据指定字段删除:
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("age",10);
userMapper.delete(wrapper);
// 方式 2
Map<String,Object> map = new HashMap<>();
map.put("age",10);
userMapper.deleteByMap(map);
五、MyBatis-Plus 一键生成(逆向工程)
1、导入如下依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
2、新建一个 Main 类,main 方法代码如下:
public class Main {
public static void main(String[] args) {
// 创建 AutoGenerator 对象
AutoGenerator autoGenerator = new AutoGenerator();
// 数据源
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/curdtest?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
autoGenerator.setDataSource(dataSourceConfig);
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
globalConfig.setOpen(false);
globalConfig.setAuthor("xxx");
autoGenerator.setGlobalConfig(globalConfig);
// 包信息
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.study");
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setMapper("mapper");
packageConfig.setEntity("entity");
autoGenerator.setPackageInfo(packageConfig);
// 配置策略
StrategyConfig strategyConfig = new StrategyConfig();
// setInclude() 可指定生成部分表
strategyConfig.setEntityLombokModel(true);
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
autoGenerator.setStrategy(strategyConfig);
// 一键生成
autoGenerator.execute();
}
}
注意数据库配置参数(如用户名与密码)要进行相应修改。
运行上方的 main 方法即可自动生成 entity
、service
、serviceImpl
、controller
的代码,即将数据库中的各个表逆向生成我们的各层代码,如果只需生成部分表,可通过 StrategyConfig.setInclude()
指定。
其中的 service
层代码也帮我们封装好了,我们可以像调用 mapper
层一样调用 service
层来完成简单的单表操作。
补充 controller
层代码即可:
/**
* <p>
* 前端控制器
* </p>
*
* @author xxx
* @since 2021-02-26
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserServiceImpl userService;
public Map<String, Object> resp(Object data) {
Map<String, Object> map = new HashMap<>();
map.put("code", 200);
map.put("msg", "success");
map.put("data", data);
return map;
}
@GetMapping("/")
public Map<String, Object> index() {
return resp(userService.list());
}
@GetMapping("/{id}")
public Map<String, Object> queryOne(@PathVariable("id") int id) {
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("id", id);
return resp(userService.list(wrapper));
}
@PostMapping("/")
public Map<String, Object> insert(@RequestBody User user) {
userService.save(user);
return resp(null);
}
@PutMapping("/")
public Map<String, Object> update(@RequestBody User user) {
userService.updateById(user);
return resp(null);
}
@DeleteMapping("/{id}")
public Map<String, Object> deletOne(@PathVariable("id") int id) {
userService.removeById(id);
return resp(null);
}
}
在 Spring Boot 程序入口中开启 mapper 扫描:
@SpringBootApplication
@MapperScan("com.study.mapper")
public class MybatisPlusAutoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusAutoApplication.class, args);
}
}
启动程序,测试其中的一个接口,基本的项目环境已经搭建完毕:
可以看到,我们几乎没有做什么,就能很快生成基本的 REST 接口,用起来挺舒服的哈哈哈。