学习目标
1.mybatis-plus简介
2.mybatis-plus的基本使用
3.代码生成器
4.分页
5.条件构造器
1.mybatis-plus简介:
1.1简介:
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。
2.特性
-
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
-
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
-
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
-
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
-
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
-
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
-
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
-
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
2.mybatis-plus的基本使用
2.1.导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
注意:
这些是核心依赖,本项目还用到了mysql驱动、c3p0、日志(slf4j-api,slf4j-log4j2)、lombok。集成mybatis-plus要把mybatis、mybatis-spring去掉,避免冲突;lombok是一个工具,添加了这个依赖,开发工具再安装Lombok插件,就可以使用它了,最常用的用法就是在实体类中使用它的@Data注解,这样实体类就不用写set、get、toString等方法了。关于Lombok的更多用法,请自行百度。
2.2 Lombok插件的安装
2.3 application.properties配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/eshop?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
#配置文件位置
mybatis-plus.config-location=classpath:mybatis-config.xml
#实体包名
mybatis-plus.type-aliases-package=com.hp.java09_springboot
#映射文件位置
mybatis-plus.mapper-locations=classpath:mappers/*.xml
logging.file.name=myapp.log
logging.level.com.hp=debug
2.4 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
@MapperScan("com.hp.java09_springboot.mapper")
@SpringBootApplication
public class Java09SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(Java09SpringbootApplication.class, args);
}
}
2.5 编写实体类
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
@TableName("s_user")//mybatis-plus 配置表名
public class User {
@TableId //当前属性作为主键
private String id;
private String username;
private String password;
private long type;
private String img;
}
2.6 编写Mapper类 UserMapper.java
public interface UserMapper extends BaseMapper<User> {
}
2.7 测试
@RunWith(SpringRunner.class)
@SpringBootTest
class Java09SpringbootApplicationTests {
@Autowired(required = false)
private UserMapper userMapper;
@Test
void contextLoads() {
//查询所有
List<User> users = userMapper.selectList(null);
for(User user:users){
System.out.println(user);
}
//使用eq方法根据数据库的字段查找
/*List<User> users =userMapper.selectList(new QueryWrapper<User>().eq("type",1)
.eq("password",123));*/
//使用eq方法根据实体类属性查找
/*List<User> users =userMapper.selectList(new QueryWrapper<User>().lambda().eq(User::getId,"0"));
users.forEach(System.out::println);*/
}
}
控制台输出
User(id=0, username=admin, password=123, type=1, img=9b1992b60a0c.jpg)
User(id=001, username=z2222, password=111, type=1, img=jkhnhn)
User(id=0874b0ef4bc842a98378e57891fc8aaf, username=huahao11, password=e10atgfh, type=1, img=)
User(id=1f7dcef8a1, username=盘江峰999, password=123456, type=1, img=http://localhost:8888/upload/45907f192c11475d8071488f4a9cb3fe.jpg)
User(id=375556f397, username=lanjian, password=12345612456858552, type=0, img=kkk.jpg)
User(id=432ab81f72694caba2ae6a4418779175, username=huangjinjin, password=202cb962ac59075b964b07152d234b70, type=1, img=null)
User(id=4e4758b84a, username=mmm, password=72d8b7c77f6c0e591d6d735c02dc95ff, type=1, img=aff24260ff62.jpg)
User(id=794248ad767c48408ceaff6ea12a8d06, username=wudi, password=e10adc3949ba59abbe56e057f20f883e, type=0, img=null)
User(id=7ea0bedd48, username=wangwu, password=b32aff4981e9917c470cb691387a3822, type=1, img=0d64ed7427f2.jpg)
User(id=9fe3d0367b, username=zhaoliu, password=3ef1a23f87a2bd31769c4742c71b6f4d, type=1, img=18d4495f5977.jpg)
User(id=a0ca9ba65d644d858e3886a4f428b447, username=lisi2, password=123456, type=1, img=1520231eb075.jpg)
User(id=ac144d77b7274e1099b0017facfb49fa, username=zhangsan12, password=6071c25cf0913649ef7df6d605d52e0f, type=1, img=6b0eb719abe6.jpg)
User(id=accfb0d969, username=张三, password=333, type=1, img=xx.jpg)
User(id=c73f3ade05, username=wpsads, password=123454, type=1, img=http://localhost:8888/upload/c186e9d522d844ff97593c638e2f4ff7.jpg)
User(id=d25fc33e6d, username=zs, password=123456, type=1, img=http://localhost:8888/upload/362be3b9582b4ff9aedb062deed75878.jpg)
3.代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
3.1添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("erp");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("lanjian");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/blb_erp?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("erp");
pc.setParent("com.hp");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mappers/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude("user,user_role,role,functions,role_fun".split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
4.分页
4.1 在启动类中加入分页插件
spring xml方式
<!-- spring xml 方式 -->
<property name="plugins">
<array>
<bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
<property name="sqlParser" ref="自定义解析类、可以没有"/>
<property name="dialectClazz" value="自定义方言类、可以没有"/>
<!-- COUNT SQL 解析.可以没有 -->
<property name="countSqlParser" ref="countSqlParser"/>
</bean>
</array>
</property>
<bean id="countSqlParser" class="com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize">
<!-- 设置为 true 可以优化部分 left join 的sql -->
<property name="optimizeJoin" value="true"/>
</bean>
spring-boot方式
//Spring boot方式
@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public class MybatisPlusConfig {
// 旧版
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
4.2 Mapper 和Service 编写分页方法相同
public interface UserMapper extends BaseMapper<User> {
//page作为分页的参数
IPage<User> selectPage(Page<User> page);
}
public interface IUserService extends IService<User> {
//page
IPage<User> getPage(Page<User> page );
}
4.3 UserMapper.xml 等同于编写一个普通 list 查询,mybatis-plus 自动替你分页
<select id="selectPage" resultType="com.baomidou.cloud.entity.User">
SELECT id,name FROM user
</select>
4.4ServiceImpl编写
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService {
@Autowired(required = false)
private UserMapper userMapper;
@Override
public IPage<User> getPage(Page<User> page) {
return userMapper.selectPage(page);
}
}
4.5 Controller编写
@Controller
@RequestMapping("user")
public class UserController {
@Autowired(required = false)
private IUserService userService;
@ResponseBody
@RequestMapping("users")
public JsonResult findPage(@RequestParam(value = "current",required = false,defaultValue = "1")Integer current){
try {
Page<User> page = new Page<>(current, 10);
//传入分页参数,获得分页结果
IPage<User> result = userService.getPage(page);
System.out.println(result.getRecords());
return new JsonResult(1,"ok",result);
} catch (Exception e) {
e.printStackTrace();
return new JsonResult(1,null,null);
}
}
}
5.条件构造器
需求:
我们需要分页查询 tb_employee 表中,年龄在 18~50 之间性别为男且姓名为 xx 的所有用户,这时候我们该如何实现上述需求呢?
使用MyBatis : 需要在 SQL 映射文件中编写带条件查询的 SQL(XML文件),并用PageHelper 插件完成分页. 实现以上一个简单的需求,往往需要我们做很多重复单调的工作。
使用MP: 依旧不用编写 SQL 语句,MP 提供了功能强大的条件构造器 ------ EntityWrapper。
条件构造器:
-
allEq(全部等于)
例1:(allEq({id:1,name:“老王”,age:null})—>id = 1 and name = ‘老王’ and age is null)
例2:(allEq({id:1,name:“老王”,age:null}, false)—>id = 1 and name = ‘老王’) -
eq(等于)
例:(eq(“name”, “老王”)—>name = ‘老王’) -
ne(不等于)
例:(ne(“name”, “老王”)—>name <> ‘老王’) -
gt(大于)
例:(gt(“age”, 18)—>age > 18) -
ge(大于等于)
例:(ge(“age”, 18)—>age >= 18) -
lt(小于)
例:(lt(“age”, 18)—>age < 18) -
le(小于等于)
例:(le(“age”, 18)—>age <= 18) -
between(BETWEEN 值1 AND 值2)
例:(between(“age”, 18, 30)—>age between 18 and 30) -
notBetween(NOT BETWEEN 值1 AND 值2)
例:(notBetween(“age”, 18, 30)—>age not between 18 and 30) -
like(LIKE ‘%值%’)
例:(like(“name”, “王”)—>name like ‘%王%’) -
notLike(NOT LIKE ‘%值%’)
例:(notLike(“name”, “王”)—>name not like ‘%王%’) -
likeLeft(LIKE ‘%值’)
例:(likeLeft(“name”, “王”)—>name like ‘%王’) -
likeRight(LIKE ‘值%’)
例:(likeRight(“name”, “王”)—>name like ‘王%’) -
isNull(字段 IS NULL)
例:(isNull(“name”)—>name is null) -
in(字段 IN (v0, v1, …))
例:(in(“age”, 1, 2, 3)—>age in (1,2,3)) -
notIn(字段 NOT IN (v0, v1, …))
例:(notIn(“age”, 1, 2, 3)—>age not in (1,2,3)) -
inSql(字段 IN ( sql语句 ))
例1:(inSql(“age”, “1,2,3,4,5,6”)—>age in (1,2,3,4,5,6))
例2:(inSql(“id”, “select id from table where id < 3”)—>id in (select id from table where id < 3) -
notInSql(字段 NOT IN ( sql语句 ))
例1:(notInSql(“age”, “1,2,3,4,5,6”)—>age in (1,2,3,4,5,6))
例2:(notInSql(“id”, “select id from table where id < 3”)—>id in (select id from table where id < 3)
-groupBy(分组:GROUP BY 字段, …)
例:(例: groupBy(“id”, “name”)—>group by id,name) -
orderByAsc(排序:ORDER BY 字段, … ASC)
例:(orderByAsc(“id”, “name”)—>order by id ASC,name ASC) -
orderByDesc(排序:ORDER BY 字段, … DESC)
-例:(orderByDesc(“id”, “name”)—>order by id DESC,name DESC) -
orderBy(排序:ORDER BY 字段, …)
例:(orderBy(true, true, “id”, “name”)—>order by id ASC,name ASC) -
having(HAVING ( sql语句 ))
例1:(having(“sum(age) > 10”)—>having sum(age) > 10)
例2:(having(“sum(age) > {0}”, 11)—>having sum(age) > 11) -
func(func 方法(主要方便在出现if…else下调用不同方法能不断链))
例:(func(i -> if(true) {i.eq(“id”, 1)} else {i.ne(“id”, 1)})) -
or(拼接 OR)
注意事项:主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)
例:(eq(“id”,1).or().eq(“name”,“老王”)—>id = 1 or name = ‘老王’) -
or(OR 嵌套)
例:(or(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>or (name = ‘李白’ and status <> ‘活着’)) -
and(AND 嵌套)
例:(and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>and (name = ‘李白’ and status <> ‘活着’)) -
nested(正常嵌套 不带 AND 或者 OR)
例:(nested(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>(name = ‘李白’ and status <> ‘活着’))
了解更多请参考官网:https://mp.baomidou.com/