利用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);
List<ParameterMapping> parameterMappings = 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;