利用mybatis拦截器做数据权限管理,拦截sql并分析、修改然后重新set。然而有的生效有的不生效。控制台打印的信息表示所有的sql都是修改成功的,那么问题在于重新set的方法。
一开始用的方法是这个:
private void setCurrentSql(Invocation invo, String sql) {
MappedStatement mappedStatement = getMappedStatement(invo);
Object[] args = invo.getArgs();
Object paramObj = args[PARAM_OBJ_INDEX];
BoundSql boundSql = mappedStatement.getBoundSql(paramObj);
ReflectUtil.setFieldValue(boundSql, "sql", sql);
}
通过反射去修改boundSql的sql属性的值,但是有问题。
后来改用这个方法:
private void setCurrentSql(Invocation invo, String sql) {
BoundSql boundSql = getBoundSql(invo);
ListparameterMappings = boundSql.
getParameterMappings();
Object paramObj = boundSql.getParameterObject();
MappedStatement mappedStatement = getMappedStatement(invo);
Configuration configuration = mappedStatement.getConfiguration();
BoundSql newBoundSql = new BoundSql(configuration, sql,
parameterMappings, paramObj);
for (ParameterMapping parameterMapping : parameterMappings) {
String prop = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(prop)) {
Object param = boundSql.getAdditionalParameter(prop);
newBoundSql.setAdditionalParameter(prop, param);
}
}
BoundSqlSource newSqlSource = new BoundSqlSource(newBoundSql);
MappedStatement newMappedStatement = copyFromMappedStatement(
mappedStatement, newSqlSource);
Object[] args = invo.getArgs();
args[MAPPED_STATEMENT_INDEX] = newMappedStatement;
}
问题解决。还有一种方法,看起来更简洁:
private void setCurrentSql(Invocation invo, String sql) {
MappedStatement mappedStatement = getMappedStatement(invo);
Object[] args = invo.getArgs();
Object paramObj = args[PARAM_OBJ_INDEX];
BoundSql boundSql = mappedStatement.getBoundSql(paramObj);
BoundSqlSource boundSqlSource = new BoundSqlSource(boundSql);
MappedStatement newMappedStatement = copyFromMappedStatement(
mappedStatement, boundSqlSource);
MetaObject metaObject = MetaObject.forObject(newMappedStatement,
new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
new DefaultReflectorFactory());
metaObject.setValue("sqlSource.boundSql.sql", sql);
args[MAPPED_STATEMENT_INDEX] = newMappedStatement;
}
上面用到的方法getMappedStatement:
private MappedStatement getMappedStatement(Invocation invo) {
Object[] args = invo.getArgs();
Object mappedStatement = args[MAPPED_STATEMENT_INDEX];
return (MappedStatement) mappedStatement;
}
私有内部类BoundSqlSource:
private class BoundSqlSource implements SqlSource {
private BoundSql boundSql;
private BoundSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}
另外还有:
private static final int MAPPED_STATEMENT_INDEX = 0;
private static final int PARAM_OBJ_INDEX = 1;