目录
1 、Mybatis-Plus简介
2 、快速入门
2.1、 创建数据库及表
2.2 工程搭建
2.2.1 创建springBoot工程
?
2.2.2 导入依赖
2.2.3 配置application.yml
2.2.4 启动类
2.2.4 编写pojo
2.2.5 编写mapper接口和配置文件
2.2.6?编写测试用例,加入junit的依赖,测试类不能使用Test类名,测试类的包目录和启动类的路径一致
3 通用CRUD
3.1插入操作
3.1.1、方法定义:
3.1.2、测试用例:?
3.1.4、@TableField
3.2、更新操作?
3.2.1、根据id更新
3.2.2、根据条件更新
3.3、删除操作?
3.3.1、deleteById
3.3.2、deleteByMap ?
?3.3.3、delete
3.3.4、deleteBatchIds ?
?3.4、查询操作
3.4.1、selectById单个查询
3.4.2、selectBatchIds ?批量查询
3.4.3、selectOne ?根据条件查询一条数据
3.4.4、selectCount ?根据条件,查询总条数
?3.4.5、selectList 根据条件查询全部记录
?3.4.6、selectPage 根据条件查询全部并分页
?3.5、SQL注入的原理
4、配置
4.1、基本配置
4.1.1、confifigLocation
4.1.2、mapperLocations
4.1.3、typeAliasesPackage
4.2、进阶配置
4.2.1、mapUnderscoreToCamelCase 是否自动开启驼峰命名映射
4.3、DB 相关策略配置
4.3.1、idType
4.3.2、tablePrefifix
5、条件构造器
5.1、allEq
?5.2、基本比较操作
5.3、模糊查询 ?
?5.4、排序
?5.5、逻辑查询
5.6、select
5.7、lambda?
6、Mybatisplus的service的封装
6.1、com.baomidou.mybatisplus.extension.service.IService接口
6. 2、com.baomidou.mybatisplus.extension.service.impl.ServiceImpl类
6.3、测试用例
6.3.1、 自定义业务层接口,继承IService
6.3.2、自定义业务层实现类,继承ServiceImpl:
6.3.3、测试类:
7、代码生成器
7.1、 代码生成说明
7.2、 代码生成
7.2.1、导入依赖
7.2.2、代码生成是基于模板做的,这里采用的freemark模块来生成,把template文件夹放到resources ?
7.2.3、编写生产代码的类CodeGenerator
7.2.4、生成代码
8、MybatisX 快速开发插件
1 、Mybatis-Plus简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。该框架由baomidou(苞米豆)组织开发并且开源的。官网:mybatis.plus 或 https://mp.baomidou.com/,码云地址:baomidou: 苞米豆,为提高生产率而生!
2 、快速入门
2.1、 创建数据库及表
?
-- 创建测试表
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_name` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(20) NOT NULL COMMENT '密码',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入测试数据
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('1', 'zhangsan', '123456', '张三', '18', 'test1@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('2', 'lisi', '123456', '李四', '20', 'test2@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('3', 'wangwu', '123456', '王五', '28', 'test3@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('4', 'zhaoliu', '123456', '赵六', '21', 'test4@chen.cn');
INSERT INTO `tb_user` (`id`, `user_name`, `password`, `name`, `age`, `email`) VALUES ('5', 'sunqi', '123456', '孙七', '24', 'test5@chen.cn');
2.2 工程搭建
2.2.1 创建springBoot工程
2.2.2 导入依赖
<!-- 继承Spring boot工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--简化代码的工具包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus的springboot支持-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
?log4j.properties:
log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
2.2.3 配置application.yml
spring:
application:
name: mybatisplusspringboot
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mybatis/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.chen.mp.pojo
2.2.4 启动类
package com.chen;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author:CHENFAN
* @Date:2021/12/1418:54
*/
@SpringBootApplication
@MapperScan(basePackages = "com.chen.mp.mapper")//用于扫描mapper接口文件
public class MpApplication {
public static void main(String[] args) {
System.out.println("ss");
SpringApplication.run(MpApplication.class,args);
}
}
2.2.4 编写pojo
package com.chen.mp.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @Author:CHENFAN
* @Date:2021/12/1419:00
*/
@Data//使用lombok完成get和set
@TableName("tb_user")//对应数据库的表名
public class User {
@TableId(value = "ID",type = IdType.AUTO)
private Long id;
@TableField("USER_NAME")//此属性名称和数据库中字段名称不符合,所以显示的映射
private String userName;//此属性名称和数据库中字段名称相同,所以隐式的映射
private String password;
private String name;
private Integer age;
private String email;
}
2.2.5 编写mapper接口和配置文件
package com.chen.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chen.mp.pojo.User;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author:CHENFAN
* @Date:2021/12/1419:11
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
在resources目录下新建一个文件夹mybatis,专门存放mapper配置文件,用于扩展自定义的sql
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chen.mapper.UserMapper">
</mapper>
2.2.6?编写测试用例,加入junit的依赖,测试类不能使用Test类名,测试类的包目录和启动类的路径一致
package com.chen;
import com.chen.mp.mapper.UserMapper;
import com.chen.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @Author:CHENFAN
* @Date:2021/12/1419:07
*/
@RunWith(SpringRunner.class)//使用springrunner运行器
@SpringBootTest(classes = MpApplication.class)//启用springboot测试,加载Springboot配置文件
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
//查询所有
@Test
public void testSelectAll(){
List<User> userList = userMapper.selectList(null);
System.out.println(userList);
}
//查询一个
@Test
public void testSelectOne(){
User user = userMapper.selectById(1);
System.out.println(user);
}
//保存
@Test
public void testSave(){
User user = new User();
user.setUserName("xiaozhao");
user.setAge(40);
user.setPassword("xiaozhao");
user.setName("小赵");
user.setEmail("xiaozhao@email.com");
userMapper.insert(user);
}
//修改
@Test
public void testUpdate(){
User user = new User();
user.setId(1228242594492923909l);
user.setName("老赵");
userMapper.updateById(user);
}
//删除
@Test
public void testDelete(){
int i = userMapper.deleteById(1228242594492923909l);
}
}
3 通用CRUD
完成了demo的搭建,接下来查看我们继承的BaseMapper中的单表操作
3.1插入操作
3.1.1、方法定义:
3.1.2、测试用例:?
@Autowired private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setAge(20);
user.setEmail("test@itcast.cn");
user.setName("曹操");
user.setUserName("caocao");
user.setPassword("123456");
//返回的result是受影响的行数,并不是自增后的id
int result = this.userMapper.insert(user);
System.out.println("result = " + result);
System.out.println(user.getId()); //自增后的id会回填到对象中
如何设置id的生成策略?,MP支持的id策略(查看IdType类):
package com.baomidou.mybatisplus.annotation;
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
* <p>该类型可以通过自己注册自动填充插件进行填充</p>
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。
*/
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5);
private final int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
3.1.4、@TableField
?在MP中通过@TableField注解可以指定字段的一些属性,常常解决的问题有2个:
- 对象中的属性名和字段名不一致的问题(非驼峰)
- 对象中的属性字段在表中不存在的问题
3.2、更新操作?
?在MP中,更新操作有2种,一种是根据id更新,另一种是根据条件更新。
3.2.1、根据id更新
方法定义:
?测试:
@Autowired
private UserMapper userMapper;
@Test
public void testUpdateById() {
User user = new User();
user.setId(6L); //主键
user.setAge(21); //更新的字段
//根据id更新,更新不为null的字段
userMapper.updateById(user); }
3.2.2、根据条件更新
方法定义:
?测试:
第一种:通过QueryMapper对象
@Autowired private UserMapper userMapper;
@Test
public void testUpdate() {
User user = new User();
user.setAge(22); //更新的字段
QueryWrapper<User> wrapper = new QueryWrapper<>();
//更新的条件
wrapper.eq("id", 6);
//执行更新操作
int result = this.userMapper.update(user, wrapper);
System.out.println("result = " + result);
第二种:?UpdateWrapper对象
@Test
public void testUpdate() {
//更新的条件以及字段
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 6).set("age", 23);
//执行更新操作
int result = this.userMapper.update(null, wrapper);
System.out.println("result = " + result);
}
3.3、删除操作?
3.3.1、deleteById
方法定义:
?测试用例:
@Autowired
private UserMapper userMapper;
@Test
public void testDeleteById() {
//执行删除操作
int result = this.userMapper.deleteById(6L);
System.out.println("result = " + result);
}
3.3.2、deleteByMap ?
方法定义:
测试:
@Autowired
private UserMapper userMapper;
@Test
public void testDeleteByMap() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("age",20);
columnMap.put("name","张三");
//将columnMap中的元素设置为删除的条件,多个之间为and关系
//执行的sql语句:DELETE FROM tb_user WHERE name = ? AND age = ?
int result = this.userMapper.deleteByMap(columnMap);
System.out.println("result = " + result);
}
?3.3.3、delete
方法定义:
?测试:
@Test
public void testDeleteByMap() {
User user = new User();
user.setAge(20);
user.setName("张三"); //将实体对象进行包装,包装为操作条件
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
int result = this.userMapper.delete(wrapper);
System.out.println("result = " + result);
}
3.3.4、deleteBatchIds ?
方法定义:
测试:
@Test
public void testDeleteByMap() {
//根据id集合批量删除
int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L)); System.out.println("result = " + result);
}
?3.4、查询操作
MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分页查询等操作。
3.4.1、selectById单个查询
方法定义:
?测试:
@Autowired
private UserMapper userMapper;
@Test
public void testSelectById() {
//根据id查询数据
User user = this.userMapper.selectById(2L);
System.out.println("result = " + user);
}
3.4.2、selectBatchIds ?批量查询
方法定义:
?测试:
@Autowired
private UserMapper userMapper;
@Test
public void testSelectBatchIds() {
//根据id集合批量查询
List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));
for (User user : users) {
System.out.println(user);
}
}
3.4.3、selectOne ?根据条件查询一条数据
方法定义:
?测试:
@Test
public void testSelectOne() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.eq("name", "李四");
//根据条件查询一条数据,如果结果超过一条会报错
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}
3.4.4、selectCount ?根据条件,查询总条数
方法定义:
?测试:
@Test
public void testSelectCount() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
//年龄大于23岁
wrapper.gt("age", 23);
//根据条件查询数据条数
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count = " + count);
}
?3.4.5、selectList 根据条件查询全部记录
方法定义:
?测试:
@Test
public void testSelectList() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
//年龄大于23岁
wrapper.gt("age", 23);
//根据条件查询数据
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println("user = " + user);
}
}
?3.4.6、selectPage 根据条件查询全部并分页
配置分页插件(自定义一个类):
package com.chen.mp.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
/**
* @Author:CHENFAN
* @Date:2021/12/1518:53
*/
@Configurable
@MapperScan("com.chen.mp.mapper") //设置mapper接口的扫描包
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor(); }
}
方法定义:
?测试:
@Test
public void testSelectPage() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
//年龄大于20岁
wrapper.gt("age", 20);
//参数:当前页,每页条数
Page<User> page = new Page<>(1,1);
//根据条件查询数据
IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
List<User> users = iPage.getRecords();
for (User user : users) {
System.out.println("user = " + user);
}
}
?3.5、SQL注入的原理
在
MP
中,
ISqlInjector
负责
SQL
的注入工作,它是一个接口,
AbstractSqlInjector
是它的实现类,实现关系如下:
?在AbstractSqlInjector中,主要是由inspectInject()方法进行注入的,如下:
@Override
public void inspectInject(
MapperBuilderAssistant builderAssistant, Class<?>
mapperClass) {
Class<?> modelClass = extractModelClass(mapperClass);
if (modelClass != null) {
String className = mapperClass.toString();
Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
if (!mapperRegistryCache.contains(className)) {
List<AbstractMethod> methodList = this.getMethodList();
if (CollectionUtils.isNotEmpty(methodList)) {
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
// 循环注入自定义方法
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
} else {
logger.debug(mapperClass.toString() + ", No effective injection method was found.");
}
mapperRegistryCache.add(className);
}
}
}
在实现方法中,
methodList.forEach(m
-
> m.inject(builderAssistant, mapperClass, modelClass,
tableInfo))
;
是关键,循环遍历方法,进行注入。
最终调用抽象方法
injectMappedStatement
进行真正的注入:
/**
* 注入自定义 MappedStatement
** @param mapperClass mapper 接口
* @param modelClass mapper 泛型
* @param tableInfo 数据库表反射信息
* @return MappedStatement
*/
public abstract MappedStatement injectMappedStatement(Class<?> mapperClass, Class<? > modelClass, TableInfo tableInfo);
查看该方法的实现:
?以SelectById为例查看:
public class SelectById extends AbstractMethod {
@Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;
SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),
sqlSelectColumns(tableInfo, false),
tableInfo.getTableName(),
tableInfo.getKeyColumn(),
tableInfo.getKeyProperty(),
tableInfo.getLogicDeleteSql(true, false)), Object.class);
return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);
}
}
可以看到,生成了
SqlSource
对象,再将
SQL
通过
addSelectMappedStatement方法添加到
MappedStatement
中。
4、配置
在
MP
中有大量的配置,其中有一部分是
Mybatis
原生的配置,另一部分是
MP
的配置,详情:
https://mybatis.plus/c onfifig/
下面我们对常用的配置做讲解
4.1、基本配置
4.1.1、confifigLocation
MyBatis
配置文件位置,如果您有单独的
MyBatis
配置,请将其路径配置到
confifigLocation
中。
MyBatis
Confifiguration
的具体内容请参考
MyBatis
官方文档
Spring Boot
:
mybatis-plus.config-location = classpath:mybatis-config.xml
?Spring MVC:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
4.1.2、mapperLocations
Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件)
MyBatis Mapper
所对应的
XML
文件位置,如果您在
Mapper
中有自定义方法(
XML
中有自定义实现),需要进行
该配置,告诉
Mapper
所对应的
XML
文件位置。
Spring Boot
:
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
Spring MVC
:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="mapperLocations" value="classpath*:mybatis/*.xml"/>
</bean>
4.1.3、typeAliasesPackage
MyBaits
别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在
Mapper
对应的
XML
文件中可以直接使
用类名,而不用使用全限定的类名(即
XML
中调用的时候不用包含包名)。
Spring Boot
:
mybatis-plus.type-aliases-package = com.chen.mp.pojo
Spring MVC
:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity"/>
</bean>
4.2、进阶配置
本部分(
Confifiguration
)的配置大都为
MyBatis
原生支持的配置,这意味着您可以通过
MyBatis XML
配置文件的形
式进行配置。
4.2.1、mapUnderscoreToCamelCase 是否自动开启驼峰命名映射
是否开启自动驼峰命名规则(
camel case
)映射,即从数据库列名
A_COLUMN
(下划线命名) 到?Java
属 性名 aColumn
(驼峰命名)的类似映射。
注意:
此属性在
MyBatis
中原默认值为
false
,在
MyBatis-Plus
中,此属性也将用于生成最终的
SQL
的
select body
如果您的数据库命名符合规则无需使用
@TableField
注解指定数据库字段名
示例(SpringBoot): ?
#关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在 mybatis-plus.configuration.map-underscore-to-camel-case=false
全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为
true
。
示例:
mybatis-plus.configuration.cache-enabled=false 1
4.3、DB 相关策略配置
4.3.1、idType
- 类型: com.baomidou.mybatisplus.annotation.IdType
- 默认值: ID_WORKER
全局默认主键类型,设置后,即可省略实体对象中的@TableId(type = IdType.AUTO)配置。
示例:
SpringBoot
:
mybatis-plus.global-config.db-config.id-type=auto
SpringMVC
:
<!--这里使用MP提供的sqlSessionFactory,完成了Spring与MP的整合-->
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="globalConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="idType" value="AUTO"/>
</bean>
</property>
</bean>
</property>
</bean>
4.3.2、tablePrefifix
表名前缀,全局配置后可省略
@TableName()
配置。
SpringBoot
:
mybatis-plus.global-config.db-config.table-prefix=tb_
SpringMVC
:
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="globalConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig">
<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
<property name="idType" value="AUTO"/>
<property name="tablePrefix" value="tb_"/>
</bean> </property>
</bean>
</property>
</bean>
5、条件构造器
在MP中,Wrapper接口的实现类关系如下:
可以看到,
AbstractWrapper
和
AbstractChainWrapper
是重点实现,接下来我们重点学习
AbstractWrapper
以及其子类。
说明
:
QueryWrapper(LambdaQueryWrapper)
和
UpdateWrapper(LambdaUpdateWrapper)
的父类 用于生成
sql
的
where
条件
, entity
属性也用于生成
sql
的
where
条件 注意
: entity
生成的
where
条件与 使用各个
api
生成
的
where
条件
没有任何关联行为
5.1、allEq
方法重载1:
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
个别参数说明
:
params
:
key
为数据库字段名
,
value
为字段值
null2IsNull
:
为
true
则在
map
的
value
为
null
时调用
isNull
方法
,
为
false
时则忽略
value
为
null
的
例
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 = '
老王
'
?实例1:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置条件
Map<String,Object> params = new HashMap<>();
params.put("name", "曹操");
params.put("age", "20");
params.put("password", null);
wrapper.allEq(params);
userMapper.selectList(wrapper);
结果:?
实例2:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置条件
Map<String,Object> params = new HashMap<>();
params.put("name", "曹操");
params.put("age", "20");
params.put("password", null);
wrapper.allEq(params,false);
userMapper.selectList(wrapper);
结果:?
?方法重载2:
allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
个别参数说明
:
filter
:
过滤函数
,为true时
允许设置的字段条件传入
params
与
null2IsNull
:
同上
例
1:
allEq((k,v)
-
> k.indexOf("a") > 0, {id:1,name:"
老王
",age:null})
--->
name = '
老王
'
and age is null
例
2:
allEq((k,v)
-
> k.indexOf("a") > 0, {id:1,name:"
老王
",age:null}, false)
--->
name =
'
老王
'
过滤条件为false的实例:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置条件
Map<String,Object> params = new HashMap<>();
params.put("name", "曹操");
params.put("age", "20");
params.put("password", null);
//SELECT ID,USER_NAME,password,name,age,email FROM tb_user
//此时filter结果为false,不传入比对条件
wrapper.allEq((k, v) -> (k.equals("na") || k.equals("ag")),params);
?结果:
?过滤条件为true的实例:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置条件
Map<String,Object> params = new HashMap<>();
params.put("name", "曹操");
params.put("age", "20");
params.put("password", null);
//SELECT ID,USER_NAME,password,name,age,email FROM tb_user WHERE name = ? AND age = ?
wrapper.allEq((k, v) -> (k.equals("name") || k.equals("age")),params);
userMapper.selectList(wrapper);
结果:
?5.2、基本比较操作
eq
????????等于 =
ne
????????不等于 <>
gt
????????大于 >
ge
????????大于等于 >=
lt
????????小于 <
le
????????小于等于 <=
between
????????BETWEEN 值
1 AND
值
2
notBetween
????????NOT BETWEEN 值
1 AND
值
2
in
????????字段 IN (value.get(0), value.get(1), ...)
notIn
????????字段 NOT IN (v0, v1, ...)??
测试用例:?
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("password", "123456") .ge("age", 20) .in("name", "李四", "王五", "赵六");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) { System.out.println(user); }
结果:
5.3、模糊查询 ?
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 '
王
%'
测试实例:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name LIKE ?
//Parameters: %陈%(String) wrapper.like("name", "c陈");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
?5.4、排序
orderBy
????????排序:ORDER BY
字段
, ...
????????例:
orderBy(true, true, "id", "name")
--->
order by id ASC,name ASC
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
测试用例:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user ORDER BY age DESC wrapper.orderByDesc("age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) { System.out.println(user);
}
?5.5、逻辑查询
or
????????拼接 OR
????????主动调用 or
表示紧接着下一个
方法
不是用
and
连接
!(
不调用
or
则默认为使用
and
连接
)
and
????????AND 嵌套
????????例:
and(i
-
> i.eq("name", "
李白
").ne("status", "
活着
"))
--->
and (name = '
李白
' and status
<> '
活着
')
?测试用例:
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name","李四").or().eq("age", 24);
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) { System.out.println(user);
}
5.6、select
在
MP
查询中,默认查询所有的字段,如果有需要也可以通过
select
方法进行指定字段。
测试用例:
//SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "李四") .or() .eq("age", 24)
.select("id", "name", "age");
List<User> users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user);
}
5.7、lambda?
MP 对于查询 Wrapper API 提供了 LambdaQueryWrapper 来很好的解决此问题。通过 Lambda 方法引用,获得实体类属性和表的对应映射关系,再做表的字段查询。
测试用例:
//构建 LambdaQueryWrapper
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//使用 LambdaQueryWrapper 构建查询条件
lambdaQueryWrapper.eq(User::getName, "李四")
.or()
.eq(User::getAge, 24);
//进行信息查询
List<User> users = this.customerMapper.selectList(lambdaQueryWrapper);
for (User user : users) {
System.out.println(user);
}
6、Mybatisplus的service的封装
Mybatis-Plus为了开发更加快捷,对业务层也进行了封装,直接提供了相关的接口和实现类。我们在进行业务层开发时,可以继承它提供的接口和实现类,使得编码更加高效。
6.1、com.baomidou.mybatisplus.extension.service.IService接口
该接口是一个泛型接口,里面提供了很多方法,包括基本的增删改查。
6. 2、com.baomidou.mybatisplus.extension.service.impl.ServiceImpl类
该类实现了上面接口中的所有方法。
6.3、测试用例
6.3.1、 自定义业务层接口,继承IService
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
6.3.2、自定义业务层实现类,继承ServiceImpl:
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}
6.3.3、测试类:
@Autowired
private UserService userService;
@Test
public void testInsert() {
User user = new User();
user.setEmail("123@chen.cn");
user.setAge(301);
user.setUserName("caocao1");
user.setName("曹操1");
user.setPassword("123456");
userService.save(user);
//获取自增长后的id值, 自增长后的id值会回填到user对象中
System.out.println("id => " + user.getId());
}
7、代码生成器
7.1、 代码生成说明
当有一个新的业务实现时,对接口的功能实现上,我们通常来说需要构建下面的信息:
-
PO类 数据库表和实体类的映射 Java Bean。 -
DAO层 需要编写接口 Mapper ,接口 Mapper 需要去继承 MP 中的 BaseMapper 接口。 -
Service层 编写 Service 层接口和实现类。业务接口需要去继承 MP 中的 IService,业务实现类需要继承 MP 中的 ServiceImpl 和 实现业务接口。 -
Controller层 编写 Controller 并标注 Spring MVC 中的相关注解。
从上面的各类代码中可以放下,代码都是模板性的,如果用手工copy、修改的方式来实现,太烦人也没效率,而这时就是代码生成器小展身手的时候,使用代码生成器生成模板性的代码,减少手工操作的繁琐,集中精力在业务开发上,提升开发效率。
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Mapper接口、Entity实体类、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率
7.2、 代码生成
7.2.1、导入依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.20</version>
</dependency>
7.2.2、代码生成是基于模板做的,这里采用的freemark模块来生成,把template文件夹放到resources ?
7.2.3、编写生产代码的类CodeGenerator
package com.chen.mp.generator;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* MyBatis-Plus 代码生成类
*/
public class CodeGenerator {
// TODO 修改服务名以及数据表名
private static final String SERVICE_NAME = "mp";
private static final String DATA_SOURCE_USER_NAME = "root";
private static final String DATA_SOURCE_PASSWORD = "123";
private static final String[] TABLE_NAMES = new String[]{
"tb_user"
};
// TODO 默认生成entity,需要生成DTO修改此变量
// 一般情况下要先生成 DTO类 然后修改此参数再生成 PO 类。
private static final Boolean IS_DTO = false;
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 选择 freemarker 引擎,默认 Velocity
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setFileOverride(true);
gc.setOutputDir(System.getProperty("user.dir") + "/src/main/java");
gc.setAuthor("chenfan");
gc.setOpen(false);
gc.setSwagger2(false);
gc.setServiceName("%sService");
gc.setBaseResultMap(true);
gc.setBaseColumnList(true);
if (IS_DTO) {
gc.setSwagger2(true);
gc.setEntityName("%sDTO");
}
mpg.setGlobalConfig(gc);
// 数据库配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setDbType(DbType.MYSQL);
dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&useSSL=false&characterEncoding=utf8");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername(DATA_SOURCE_USER_NAME);
dsc.setPassword(DATA_SOURCE_PASSWORD);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(SERVICE_NAME);
pc.setParent("com.chen");
pc.setServiceImpl("service.impl");
pc.setXml("mapper");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return System.getProperty("user.dir") + "/src/main/resources/mapper/" +
tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 设置模板
TemplateConfig tc = new TemplateConfig();
mpg.setTemplate(tc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude(TABLE_NAMES);
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
// Boolean类型字段是否移除is前缀处理
strategy.setEntityBooleanColumnRemoveIsPrefix(true);
strategy.setRestControllerStyle(true);
mpg.setStrategy(strategy);
mpg.execute();
}
}
参数说明:
7.2.4、生成代码
执行CodeGenerator类中的main方法,就可以生成文件
8、MybatisX 快速开发插件
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins ->输入 mybatisx 搜索并安装。
功能:
-
Java 与 XML 调回跳转 -
Mapper 方法自动生成 XML
|