mybatis-plus的TenantLineInnerInterceptor插件使用

一、多租户

        多租户技术(英语:multi-tenancy technology)或称多重租赁技术,是一种软件架构技术,它是在探讨与实现如何于多用户的环境下共用相同的系统或程序组件,并且仍可确保各用户间数据的隔离性。

        多租户技术可以实现多个租户之间共享系统实例,同时又可以实现租户的系统实例的个性化定制。通过使用多租户技术可以保证系统共性的部分被共享,个性的部分被单独隔离。通过在多个租户之间的资源复用,运营管理维护资源,有效节省开发应用的成本。

        多租户技术的实现重点,在于不同租户间应用程序环境的隔离(application context isolation)以及数据的隔离(data isolation),以维持不同租户间应用程序不会相互干扰,同时数据的保密性也够强。

二、TenantLineInnerInterceptor插件使用

在MybatisPlusConfig类中添加多租户插件。

@Configuration
@MapperScan("com.example.demo.*")
public class MybatisPlusConfig {

    @Resource
    TenantIgnoreTable tenantIgnoreTable;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //多租户插件
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
           @Override
            public Expression getTenantId() {
                RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
                if (requestAttributes == null ) {
                    throw new RuntimeException(ContainsExp.TOKEN_406);
                }
                String tenantId= ((ServletRequestAttributes) requestAttributes).getRequest().getHeader("tenantId");
                return new LongValue(tenantId);
            }

            // 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件
            @Override
            public boolean ignoreTable(String tableName) {
                // 非http请求,代码业务逻辑,不校验tenantId
                RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
                String tenantId= ((ServletRequestAttributes) requestAttributes).getRequest().getHeader("tenantId");
                if(StringUtils.isBlank(tenantId)){
                    return  true;
                }
                boolean res= false;
                for (String tenantIgnoreTableName:tenantIgnoreTable.getTable()) {
                    res= res|| tenantIgnoreTableName.equals(tableName);
                }
                return res;
            }
        }));

        // 针对 update 和 delete 语句 作用: 阻止恶意的全表更新删除
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());

        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return interceptor;
    }
}

 多租户筛选列表。

@Data
@Component
@ConfigurationProperties(prefix = "tenant.ignore") // 配置文件的前缀
public class TenantIgnoreTable {
    /*
     * 多租户筛选查询,忽略表列表
     */
    private List<String> table;
}

bootstrap.yml配置类。

# 多租户筛选查询,忽略表列表
tenant:
   ignore:
      #该表列表下均忽略
      table: [users, students, teachers, schools...]

实体类Users

/**
 * 用户实体对应表 users
 */
@Data
@Accessors(chain = true)
public class Users {
    private Long id;
    /**
     * 租户 ID
     */
    private Long tenantId;
    private String name;

    @TableField(exist = false)
    private String addrName;

}

UserMapper

/**
 * MP 支持不需要 UsersMapper.xml 这个模块演示内置 CRUD 咱们就不要 XML 部分了
 */
public interface UsersMapper extends BaseMapper<Users> {

    /**
     * 自定义SQL:默认也会增加多租户条件
     * 参考打印的SQL
     * @return
     */
    Integer myCount();

    List<Users> getUserAndAddr(@Param("username") String username);

    List<Users> getAddrAndUser(@Param("name") String name);
}

 如果你想在某个mapper中的某个方法中屏蔽这个租户隔离方法,可以这么写。

各属性返回 true 表示不走插件(在配置了插件的情况下,不填则默认表示 false)

@InterceptorIgnore(tenantLine = "true")
Users loginById(@Param("userId") Integer userId);

UserMapper.xml

<?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.example.demo.repository.UsersMapper">

    <select id="myCount" resultType="java.lang.Integer">
        select count(1) from users
    </select>

    <select id="getUserAndAddr" resultType="com.example.demo.entity.Users">
        select u.id, u.name, a.name as addr_name
        from users u
        left join user_addr a on a.user_id=u.id
        <where>
            <if test="username!=null">
                u.name like concat(concat('%',#{username}),'%')
            </if>
        </where>
    </select>

    <select id="getAddrAndUser" resultType="com.example.demo.entity.Users">
        select a.name as addr_name, u.id, u.name
        from user_addr a
        left join users u on u.id=a.user_id
        <where>
            <if test="name!=null">
                a.name like concat(concat('%',#{name}),'%')
            </if>
        </where>
    </select>
</mapper>

单元测试

@SpringBootTest
public class TenantTest {
    @Resource
    private UsersMapper mapper;

    @Test
    public void aInsert() {
        Users user = new Users();
        user.setName("一一");
        Assertions.assertTrue(mapper.insert(user) > 0);
        user = mapper.selectById(user.getId());
        Assertions.assertTrue(1 == user.getTenantId());
    }

}

三、结果分析 

执行insert方法之后,可以看到sql语句中自动拼接了租户屏蔽条件。

总之一定要记住,遇到问题了就看日志,学会看日志了,解决问题的速度也会快很多。

 数据库结果。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Mybatis-Plus分页插件是一个基于Mybatis的分页插件,可以方便地实现分页查询功能。使用插件,只需要在Mapper接口中定义一个继承BaseMapper的接口,并在方法中使用Page对象进行分页查询即可。 具体使用步骤如下: 1. 引入Mybatis-Plus分页插件依赖 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> ``` 2. 定义Mapper接口 在Mapper接口中继承BaseMapper,并定义一个方法,使用Page对象进行分页查询。例如: ``` public interface UserMapper extends BaseMapper<User> { List<User> selectUserPage(Page<User> page, @Param("name") String name); } ``` 3. 在Service中调用Mapper方法 在Service中调用Mapper方法,传入Page对象和查询条件,例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public IPage<User> getUserPage(Page<User> page, String name) { return userMapper.selectUserPage(page, name); } } ``` 4. 在Controller中调用Service方法 在Controller中调用Service方法,传入Page对象和查询条件,例如: ``` @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/page") public IPage<User> getUserPage(Page<User> page, String name) { return userService.getUserPage(page, name); } } ``` 以上就是Mybatis-Plus分页插件使用步骤。通过使用插件,可以方便地实现分页查询功能,提高开发效率。 ### 回答2: Mybatis-Plus是一个基于Mybatis的增强工具,为了提高开发效率和减少重复的CRUD操作而生。其中,Mybatis-Plus分页插件是其重要的功能之一,可以帮助开发人员快速的实现数据的分页查询。 Mybatis-Plus分页插件使用非常简单,开发人员只需要在Mybatis-Plus的配置文件中进行一些简单的配置即可。以下是为您提供的Mybatis-Plus分页插件使用方法: 1.引入依赖:首先我们需要在项目中引入自己构建的mybatis-plus-boot-starter,或者直接在pom.xml中引入Mybatis-Plus对应版本的依赖。 2.配置分页插件:在mybatis-plus.yml中配置分页插件,如下所示: mybatis-plus: # 配置分页插件 configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置 Mybatis-Plus 分页插件 plugins: - interceptor: class: com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor 3.配置分页查询:在Mapper接口方法中添加分页参数,在Mapper.xml文件中添加分页查询的具体SQL语句,如下所示: //mapper 接口 public interface YourMapper extends BaseMapper<YourEntity> { IPage<YourEntity> selectPageVo(Page page, @Param("yourEntity") YourEntity yourEntity); } <!-- Mapper.xml --> <select id="selectPageVo" resultType="YourEntityVo"> select {yourEntity.*} from your_entity {yourEntity} where 1=1 <if test="yourEntity.name != null and yourEntity.name!=''"> and yourEntity.name like '%${yourEntity.name}%' </if> </select> 4.使用分页查询:在Service层中使用分页查询,如下所示: @Override public IPage<YourEntity> selectPageVo(Page<YourEntity> page, YourEntity yourEntity) { return this.getBaseMapper().selectPageVo(page, yourEntity); } 使用Mybatis-Plus分页插件,不仅可以实现简单的分页查询,而且还可以自定义查询条件、排序方式等。总之,这是一个非常方便和实用的插件,可以让开发人员更快地进行数据操作和维护。 ### 回答3: Mybatis-plus 是一款基于 Mybatis 的增强工具包,它提供了很多的快捷操作,其中就包括分页插件使用 Mybatis-plus 分页插件可以简化分页操作,提高代码的可读性和可维护性。 使用分页插件,需要先引入 Mybatis-plus 的依赖包。在 Spring Boot 中,可以通过 Gradle 或 Maven 的方式引入 Mybatis-plus 相关依赖,例如: ``` groovy dependencies { implementation 'com.baomidou:mybatis-plus-boot-starter:3.4.2' } ``` 在配置文件中加入分页插件配置: ``` yml mybatis-plus: page-params: limit: 10 # 每页显示条数 max-limit: 100 # 最大显示条数 overflow: false # 是否溢出 ``` 其中,`limit` 表示每页显示的条数,`max-limit` 表示最大显示的条数,`overflow` 表示是否允许溢出。 在 Mybatis-plus 的 Mapper 接口中定义查询方法时,需要加入 `IPage` 类型的参数,例如: ``` java import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; public interface UserMapper extends BaseMapper<User> { IPage<User> selectPageVo(Page<?> page, UserVo userVo); } ``` 其中,`Page` 类是 Mybatis-plus 中提供的分页对象,`User` 是实体类,`UserVo` 是查询参数,`selectPageVo` 方法就是查询分页方法。 在 Service 层中调用 Mapper 中定义的分页方法: ``` java @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Override public IPage<User> selectPageVo(UserVo userVo) { Page<User> page = new Page<>(); page.setCurrent(userVo.getCurrentPage()); page.setSize(userVo.getPageSize()); return baseMapper.selectPageVo(page, userVo); } } ``` 在上面的示例中,`Page` 对象中设置了分页参数,`baseMapper` 是继承自 `BaseServiceImpl` 的默认的 Mapper 对象,`selectPageVo` 方法返回分页查询结果。 最后,在 Controller 中调用 Service 方法: ``` java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @GetMapping("/page") public IPage<User> selectPageVo(UserVo userVo) { return userService.selectPageVo(userVo); } } ``` 在上面的示例中,`selectPageVo` 方法返回的就是分页查询结果。在前端展示时,可以通过获取到的 `IPage` 对象获取分页信息和查询结果,例如: ```javascript axios.get('/users/page', { params: { currentPage: 1, pageSize: 10, username: 'Tom' } }).then(res => { // 获取分页信息和查询结果 const { current, total, records } = res.data; // ... }); ``` 通过 Mybatis-plus 的分页插件,我们不仅可以简化分页操作,还可以通过配置实现一些高级功能,例如性能优化和多租户分页。因此,Mybatis-plus 的分页插件是一个非常实用的工具,值得推荐使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值