文章目录
MyBatis-Plus-Join
注意:MyBatis-Plus-Join 需要配合 MyBatis-plus 3.3.0 及以上的版本使用
demo示例:https://gitee.com/best_handsome/mybatis-plus-join-demo
官网:https://mybatisplusjoin.com/pages/quickstart/ksks.html
一、导入依赖
<!-- 添加依赖 引入 Spring Boot Starter 父工程-->
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.4.7.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
二、service层(可选)
import com.github.yulichang.base.MPJBaseService;
import com.github.yulichang.join.entity.User;
// service
public interface UserService extends MPJBaseService<User> {
}
// 实现类
@Service
public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implements UserService {
}
三、Mapper层
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.join.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends MPJBaseMapper<User> {
}
@Mapper
public interface UserAddressMapper extends MPJBaseMapper<Address> {
}
四、Entity实体类
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.github.yulichang.join.enums.Sex;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@TableName("`user`")
public class User extends BaseEntity {
@TableId
private Integer id;
private String name;
private Sex sex;
@TableLogic
private Boolean del;
}
@Data
@Accessors(chain = true)
@TableName("user_address")
public class Address extends BaseEntity{
@TableId
private Integer id;
private String address;
@TableLogic
private Boolean del;
}
4.2 基础实体类对象
@Data
public abstract class BaseEntity implements Serializable {
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 最后更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
/**
* 创建者,目前使用 SysUser 的 id 编号
*/
@TableField(fill = FieldFill.INSERT)
private String creator;
/**
* 更新者,目前使用 SysUser 的 id 编号
*
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updater;
/**
* 是否删除
*/
@TableLogic
private Boolean deleted;
}
4.3 自动注入通用属性值:
creator \ createTime \ updater \ updateTime
自定义实现MetaObjectHandler元对象字段填充控制器抽象类,实现公共字段自动写入
/**
* 通用参数填充实现类: 实现MetaObjectHandler接口
*
* 如果没有显式的对通用参数进行赋值,这里会对通用参数进行填充、赋值
*
*/
@Component
public class DefaultDBFieldHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
Date current = new Date();
// 创建时间为空,则以当前时间为插入时间
if (Objects.isNull(baseDO.getCreateTime())) {
baseDO.setCreateTime(current);
}
// 更新时间为空,则以当前时间为更新时间
if (Objects.isNull(baseDO.getUpdateTime())) {
baseDO.setUpdateTime(current);
}
String userId = ..... 这里自定义实现逻辑,获取当前登录用户
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getCreator())) {
baseDO.setCreator(userId.toString());
}
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
baseDO.setUpdater(userId.toString());
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新时间为空,则以当前时间为更新时间
Object modifyTime = getFieldValByName("updateTime", metaObject);
if (Objects.isNull(modifyTime)) {
setFieldValByName("updateTime", new Date(), metaObject);
}
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
Object modifier = getFieldValByName("updater", metaObject);
String userId = ..... 这里自定义实现逻辑,获取当前登录用户
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
setFieldValByName("updater", userId.toString(), metaObject);
}
}
}
五、cofig配置类
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Mybatis-plus: 分页插件。
*/
@Configuration
@MapperScan(basePackages = {"com.goodwe.kafkaapi.mapper"}) // 这里配置,启动类可不用配置。
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 添加分页插件
PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
// 设置请求的页面大于最大页后操作,true调回到首页,false继续请求。默认false
pageInterceptor.setOverflow(false);
// 单页分页条数限制,默认无限制
pageInterceptor.setMaxLimit(500L);
// 设置数据库类型
pageInterceptor.setDbType(DbType.SQL_SERVER);
interceptor.addInnerInterceptor(pageInterceptor);
return interceptor;
}
/**
* 禁用 MyBatis 使用过时的执行器,以确保项目,使用最新版本执行器。
*/
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
六、yml配置文件(可不配置)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 配置 Mybatis-Plus Join 插件
join:
# 是否启用 Join 优化插件
enabled: true
# 是否打印 SQL 语句
show-sql: true
SpringBoot主启动类:
添加 @MapperScan 注解,扫描 Mapper 文件夹。
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
测试类
@SpringBootTest
class JoinTest {
@Autowired
private UserMapper userMapper;
/**
* 一对多
*/
@Test
void testJoin() {
MPJLambdaWrapper<UserDO> wrapper = new MPJLambdaWrapper<UserDO>()
.selectAll(UserDO.class)
.selectCollection(AddressDO.class, UserDTO::getAddressList)
.leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId)
.orderByDesc(UserDO::getId);
List<UserDTO> list = userMapper.selectJoinList(UserDTO.class, wrapper);
list.forEach(System.out::println);
}
/**
* 简单的分页关联查询 lambda
*/
@Test
void test1() {
IPage<UserDTO> iPage = userMapper.selectJoinPage(new Page<>(1, 10), UserDTO.class,
MPJWrappers.<UserDO>lambdaJoin()
.selectAll(UserDO.class)
.select(AddressDO::getAddress)
.select(AreaDO::getProvince)
.leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId)
.leftJoin(AreaDO.class, AreaDO::getId, AddressDO::getAreaId));
iPage.getRecords().forEach(System.out::println);
}
/**
* 简单的关联查询 String
*/
@Test
void test2() {
MPJQueryWrapper<UserDO> wrapper = MPJWrappers.<UserDO>queryJoin()
.selectAll(UserDO.class)
.selectAll(AddressDO.class, "addr")
.selectAll(AreaDO.class, "a")
.selectIgnore("addr.id", "a.id", "t.del", "addr.del")
.leftJoin("user_address addr on t.id = addr.user_id")
.leftJoin("area a on a.id = addr.area_id")
.eq("t.id", 1);
List<UserDO> list = userMapper.selectList(wrapper);
list.forEach(System.out::println);
}
/**
* 简单的分页关联查询 lambda
* ON语句多条件
*/
@Test
void test3() {
IPage<UserDTO> page = userMapper.selectJoinPage(new Page<>(1, 10), UserDTO.class,
MPJWrappers.<UserDO>lambdaJoin()
.selectAll(UserDO.class)
.select(AddressDO::getAddress)
.leftJoin(AddressDO.class, on -> on
.eq(UserDO::getId, AddressDO::getUserId)
.eq(UserDO::getId, AddressDO::getUserId))
.eq(UserDO::getId, 1)
.and(i -> i.eq(UserDO::getHeadImg, "er")
.or()
.eq(AddressDO::getUserId, 1))
.eq(UserDO::getId, 1));
page.getRecords().forEach(System.out::println);
}
/**
* 简单的函数使用
*/
@Test
void test4() {
UserDTO one = userMapper.selectJoinOne(UserDTO.class, MPJWrappers.<UserDO>lambdaJoin()
.selectSum(UserDO::getId)
.selectMax(UserDO::getId, UserDTO::getHeadImg)
.leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId)
.eq(UserDO::getId, 1));
System.out.println(one);
}
/**
* 忽略个别查询字段
*/
@Test
void test6() {
IPage<UserDTO> page = userMapper.selectJoinPage(new Page<>(1, 10), UserDTO.class,
MPJWrappers.<UserDO>lambdaJoin()
.selectAll(UserDO.class)
.selectFilter(AddressDO.class, p -> true)
.select(AddressDO::getAddress)
.leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId)
.eq(UserDO::getId, 1));
page.getRecords().forEach(System.out::println);
}
/**
* 关联查询返回map
*/
@Test
void test7() {
List<Map<String, Object>> list = userMapper.selectJoinMaps(MPJWrappers.<UserDO>lambdaJoin()
.selectAll(UserDO.class)
.select(AddressDO::getAddress)
.leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId)
.eq(UserDO::getId, 1));
list.forEach(System.out::println);
}
}