mybatis-plus icon indicating copy to clipboard operation
mybatis-plus copied to clipboard

想要查询自动增加两个查询条件,用多租户插件模式是否满足?

Open xiaoyuwang1987 opened this issue 1 year ago • 6 comments

目前看好像多租户只能加一个字段是吗,能否组合,而且我只想开启查询需要加

xiaoyuwang1987 avatar Nov 30 '23 08:11 xiaoyuwang1987

可以的啊,在spring ioc容器里注册两个TenantLineInnerInterceptor就可以了 image 查询代码 image 生成的sql image

coffee-developer avatar Nov 30 '23 11:11 coffee-developer

TenantLineInnerInterceptor

但是我要设置租户的值 是从token里面获取的,如果这样是不是没办法这样做,而且我只是想查询的接口要加条件

xiaoyuwang1987 avatar Dec 04 '23 01:12 xiaoyuwang1987

租户的值和开关可以通过ThreadLocal【在拦截器注入相关值,开关可以通过注解控制】将值传递给线程上下文来进行判断,之前我是这么实现的

HillCheuang avatar Dec 04 '23 02:12 HillCheuang

租户的值和开关可以通过ThreadLocal【在拦截器注入相关值,开关可以通过注解控制】将值传递给线程上下文来进行判断,之前我是这么实现的

提供一下代码行不

xiaoyuwang1987 avatar Dec 04 '23 07:12 xiaoyuwang1987

具体代码是用在公司项目不方便透露 不过可以提供大致的代码 1.关于只在查询的时候需要加字段 可以查看mybatis-plus的源码TenantLineInnerInterceptor类里面有beforeQuery、beforePrepare、processInsert、processUpdate 若只想要查询加可以继承这个TenantLineInnerInterceptor类 processUpdate、processInsert等方法可以空实现

@Service
public class TestInterceptor extends TenantLineInnerInterceptor {


    @Autowired
    private TenantLineHandlerImpl tenantLineHandler;
    @Autowired
    private TenantProperties tenantProperties;

    public CourtCodesInterceptor(TenantLineHandler tenantLineHandler) {
        super(tenantLineHandler);
    }


    /**
     * 不处理连接数据库语句
     * @param sh
     * @param connection
     * @param transactionTimeout
     */
    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        //empty
    }

    /**
     * 不处理update语句
     * @param executor
     * @param ms
     * @param parameter
     * @throws SQLException
     */
    @Override
    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
        //empty
    }

    /**
     * 在query查询语句触发之前
     * @param executor
     * @param ms
     * @param parameter
     * @param rowBounds
     * @param resultHandler
     * @param boundSql
     * @throws SQLException
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {

        if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) return;
        if (SqlParserHelper.getSqlParserInfo(ms)) return;
      //  System.err.println("原sql为:\n" + SQLUtils.formatMySql(boundSql.getSql()));
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(parserSingle(mpBs.sql(), null));
       // System.err.println("插件sql为:\n" + SQLUtils.formatMySql(boundSql.getSql()));
    }


    /**
     * 拼接条件
     * @param currentExpression
     * @param table
     * @return
     */
    @Override
    protected Expression builderExpression(Expression currentExpression, Table table) {
        Column aliasColumn = getAliasColumn(table);

        Expression expression = tenantLineHandler.getTenantId(aliasColumn);
        if (currentExpression == null) {
            return expression;
        }
        if (currentExpression instanceof OrExpression) {
            return new AndExpression(new Parenthesis(currentExpression), expression);
        } else {
            return new AndExpression(currentExpression, expression);
        }
    }


    @Override
    protected Column getAliasColumn(Table table) {
        StringBuilder column = new StringBuilder();
        if (table.getAlias() != null) {
            column.append(table.getAlias().getName()).append(StringPool.DOT);
        }
        column.append(tenantLineHandler.getTenantIdColumn());
        return new Column(column.toString());
    }


}

2.要设置租户的值 是从token里面获取,可以配置一个拦截器

@Slf4j
public class UserInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    CommonHeader commonHeader;
    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND) {
            return false;
        }
        //1,获取名字
        String username = request.getHeader("X-Login-User");
        // 设置commonHeader
        commonHeader.setUsername(username);
        if (StringUtils.isEmpty(username)) {
            log.error("用户名不能为空,URI:" + request.getRequestURI());
            response.setStatus(200);
            response.setCharacterEncoding("UTF8");
            response.setContentType("application/json;charset=UTF8");
            response.getWriter().print(JSONObject.toJSONString(WebApiResponse.error("username为空")));
            response.flushBuffer();
            response.getWriter().close();
            return false;
        }
        return true;
    }
}
	//注入相关上下文
		@Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public CommonHeader getCommonHeader() {
        return new CommonHeader();
    }

相关租户配置逻辑

@Repository
public class TenantLineHandlerImpl implements TenantLineHandler {

    @Autowired
    TenantProperties tenantProperties;

    @Autowired
    CommonHeader commonHeader;

    @Override
    public Expression getTenantId() {
     //请求上下文
        String userName = commonHeader.getUserName();
       //你可以在此commonHeader获取token相关内容
       //相关逻辑
    }


    


    /**
     * 获取多租户的字段名
     *
     * @return String
     */
    @Override
    public String getTenantIdColumn() {
        return tenantProperties.getColumn();
    }

    /**
     * 过滤不需要根据租户隔离的表
     * 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件
     *可能表名带 ``因此需要去除
     * @param tableName 表名
     */
    @Override
    public boolean ignoreTable(String tableName) {
        //根据自己业务来是否需要过滤租户条件,可以根据线程上下文实现

    }
}

HillCheuang avatar Dec 05 '23 08:12 HillCheuang

不过我推荐你自己阅读一下mybatis-plus 租户插件的源码 根据Spring 某些特性 是可以实现你的需求

HillCheuang avatar Dec 05 '23 09:12 HillCheuang