mybatis攔截器實現(xiàn)數(shù)據(jù)權限
前端的菜單和按鈕權限都可以通過配置來實現(xiàn),但很多時候,后臺查詢數(shù)據(jù)庫數(shù)據(jù)的權限需要通過手動添加SQL來實現(xiàn)。
比如員工打卡記錄表,有id,name,dpt_id,company_id等字段,后兩個表示部門ID和分公司ID。
查看員工打卡記錄SQL為:select id,name,dpt_id,company_id from t_record
當一個總部賬號可以查看全部數(shù)據(jù)此時,sql無需改變。因為他可以看到全部數(shù)據(jù)。
當一個部門管理員權限員工查看全部數(shù)據(jù)時,sql需要在末屬添加?where dpt_id = #{dpt_id}
如果每個功能模塊都需要手動寫代碼去拿到當前登陸用戶的所屬部門,然后手動添加where條件,就顯得非常的繁瑣。
因此,可以通過mybatis的攔截器拿到查詢sql語句,再自動改寫sql。
mybatis 攔截器
MyBatis 允許你在映射語句執(zhí)行過程中的某一點進行攔截調用。默認情況下,MyBatis 允許使用插件來攔截的方法調用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
這些類中方法的細節(jié)可以通過查看每個方法的簽名來發(fā)現(xiàn),或者直接查看 MyBatis 發(fā)行包中的源代碼。 如果你想做的不僅僅是監(jiān)控方法的調用,那么你最好相當了解要重寫的方法的行為。 因為在試圖修改或重寫已有方法的行為時,很可能會破壞 MyBatis 的核心模塊。 這些都是更底層的類和方法,所以使用插件的時候要特別當心。
通過 MyBatis 提供的強大機制,使用插件是非常簡單的,只需實現(xiàn) Interceptor 接口,并指定想要攔截的方法簽名即可。
分頁插件pagehelper就是一個典型的通過攔截器去改寫SQL的。

可以看到它通過注解 @Intercepts 和簽名 @Signature 來實現(xiàn),攔截Executor執(zhí)行器,攔截所有的query查詢類方法。
我們可以據(jù)此也實現(xiàn)自己的攔截器。
點擊查看代碼
順便加了個注解 @SqlLimit,在mapper方法上加了此注解才進行數(shù)據(jù)權限過濾。
同時注解有兩個屬性,
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SqlLimit {
? ?/**
? ? * sql表別名
? ? * @return
? ? */
? ?String alis() default "";
? ?/**
? ? * 通過此列名進行限制
? ? * @return
? ? */
? ?String columnName() default "";
}
columnName表示通過此列名進行限制,一般來說一個系統(tǒng),各表當中的此列是統(tǒng)一的,可以忽略。
alis用于標注sql表別名,如 針對sql?select * from tablea as a left join tableb as b on a.id = b.id
?進行改寫,如果不知道表別名,會直接在后面拼接?where dpt_id = #{dptId}
,
那此SQL就會錯誤的,通過別名?@SqlLimit(alis = "a")
?就可以知道需要拼接的是?where a.dpt_id = #{dptId}
執(zhí)行結果
原SQL:select * from person, 數(shù)據(jù)權限替換后的SQL:select * from person where dpt_id = 234
原SQL:select * from person where id > 1, 數(shù)據(jù)權限替換后的SQL:select * from person where dpt_id = 234 and id > 1
但是在使用PageHelper進行分頁的時候還是有問題。

可以看到先執(zhí)行了_COUNT方法也就是PageHelper,再執(zhí)行了自定義的攔截器。
在我們的業(yè)務方法中注入SqlSessionFactory
@Autowired
@Lazy
private List<SqlSessionFactory> sqlSessionFactoryList;

PageInterceptor為1,自定義攔截器為0,跟order相反,PageInterceptor優(yōu)先級更高,所以越先執(zhí)行。