您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么通過MyBatis自定義插件實現簡易數據權限”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么通過MyBatis自定義插件實現簡易數據權限”吧!
一說到mybatis插件,都會想到mybatis的分頁插件。的確現在開發中用mybatis的話,一般都會用到它。它能在我們的sql語句后面添加分頁查詢條件,達到分頁查詢的效果。
由于mybatis是基于xml插件配置的所以,我們要在xml中配置自己的插件
<plugins> <plugin interceptor="com.wj.Interceptor.DataScopeInterceptor" /> //自定義插件的全類名 </plugins>
先看看一張圖 ,mybatis主要提供了下面4個接口支持攔截
編寫DataScopeInterceptor(需要實現Interceptor接口)
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class DataScopeInterceptor implements Interceptor { // 這里是每次執行操作的時候,都會進行這個攔截器的方法內 @Override public Object intercept(Invocation invocation) throws Throwable { //TODO:自已的業務處理 return invocation.proceed(); } // 主要是為了把這個攔截器生成一個代理放到攔截器鏈中 @Override public Object plugin(Object o) { return Plugin.wrap(o, this); } // 插件初始化的時候調用,也只調用一次,插件配置的屬性從這里設置進來 @Override public void setProperties(Properties properties) { } }
看看這個注解
@Signature( type = StatementHandler.class, //這是指攔截哪個接口 method = "prepare", //這個是攔截接口中的什么方法,可以在StatementHandler中找到此方法 args = {Connection.class, Integer.class}//攔截方法的參數列表)
下面我們啟動項目,執行sql查詢的時候會進入到我們的插件中。現在算是自己定義好了一個空的插件了。
ps:mybatis可以同時定義多個插件,這些插件采用責任鏈模式,通過代理對象一個一個調用下一個插件,進行執行。
項目開發中,大多項目都有權限相關的考慮,說到權限,大體分為兩類,數據權限與功能權限。數據權限一般是針對不同的角色或者用戶,查詢到不同的數據,對同一數據表或者數據源的不同條件篩選。而功能權限更多是對功能菜單的訪問權限。在不同項目中,權限設計也不同,跟系統業務,架構設計息息相關,做好權限,是非常困難的。我這里僅僅是對數據權限的一個模擬。不涉及具體實現。(這塊本來就沒有同一的處理方案)。
我這里將數據權限分為兩個類別,明細授權,條件授權
明細授權:對一個表數據,通過id進行授權,比如有個商品表,可以把指定商品的id授權給指定用戶或角色,達到該用戶或角色可以查詢到這一個指定商品。
select * from product where id = 1
條件授權:可以通過指定范圍查詢條件為某一用戶或角色進行授權
select * from product where name like '%iphone%'
上面的兩個sql很明顯的表現了這兩種授權方式的區別與聯系。我們不免會想,明細授權也可以用條件授權來實現,達到相同的效果,的確是這樣,我們這里僅僅說明兩天不同的授權方式,其實在真實的環境中,可能還會有其他的授權形式。
上面我們通過對mybatis插件的自定義,我們就可以對sql進行處理了。所以,數據權限無非就是在自定義插件中獲取到sql。在sql語句后面拼接不同的過濾條件來達到數據過濾。真實業務場景更為復雜。很多時候,不僅僅是拼接這么簡單。對sql的處理也是一件廢功夫的事情。下面看具體實現
數據權限接口,這里只寫了一個getsql的方法定義,參數為原始sql,返回值為經過處理后的sql
public interface DataScopeInterface { /** * 獲取sql * @return */ String getSql(String sql); }
DataScopeInterface有兩個不同的實現類,明細與條件
@Component("grantDataScope") @Slf4j public class GrantDataScope implements DataScopeInterface { //明細授權實現 @Override public String getSql(String sql) { //這里是獲取當前登錄用戶的id,我定義了一個登錄攔截器,通過ThreadLocal保存當前登錄的用戶。代碼就不寫出來了。比較簡單 String userId = LoginHandlerInterceptor.userLoginThreadLocal.get(); //這里模擬用戶id為1的用戶在查詢語句后面拼接id為1的過濾條件 if("1".equals(userId)){ if(sql.toLowerCase().contains("where")){ sql += ">
條件授權
@Component("ruleDataScope") @Slf4j public class RuleDataScope implements DataScopeInterface { // 條件授權實現 public String getSql(String sql) { String userId = LoginHandlerInterceptor.userLoginThreadLocal.get(); //模擬用戶為id為2的用戶加name中有ipone的數據 if("2".equals(userId)){ if(sql.toLowerCase().contains("where")){ sql += " and name like '%iphone%'"; }else { sql += " where name like '%iphone%'"; } } log.info("rule: "+ sql); return sql; } }
下面在自定義插件中編寫業務具體實現邏輯。由于我們不同的授權類型都是交給spring管理的bean,我們可以借此通過策略模式來實現授權規則的可擴展性。有不同的授權規則只需要實現DataScopeInterface接口即可。
public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); String userName = LoginHandlerInterceptor.userLoginThreadLocal.get(); // sql語句類型 Object sqlCommandType = metaStatementHandler.getValue("delegate.mappedStatement.sqlCommandType"); //只考慮了查詢 if (SqlCommandType.SELECT.equals(sqlCommandType)) { //獲取sql String sql = String.valueOf(metaStatementHandler.getValue("delegate.boundSql.sql")); //獲取DataScopeInterface的實現類集合,并循環執行sql的格式化 Map<String, DataScopeInterface> dataScopeInterfaceMap = SpringContextUtils.getBeanOfType(DataScopeInterface.class); Collection<DataScopeInterface> dataScopeInterfaces = dataScopeInterfaceMap.values(); for (DataScopeInterface dataScopeInterface : dataScopeInterfaces) { sql = dataScopeInterface.getSql(sql); } log.info("sql --> " + sql); //重新設置sql metaStatementHandler.setValue("delegate.boundSql.sql", sql); } return invocation.proceed(); }
啟動項目,模擬用戶id為1的用戶登錄,返回了一條記錄,達到了過濾的效果。
2019-08-24 14:07:05,496 DEBUG (BaseJdbcLogger.java:145)- ==> Preparing: select * from product where id = 1 2019-08-24 14:07:05,496 DEBUG (BaseJdbcLogger.java:145)- ==> Parameters: 2019-08-24 14:07:05,498 DEBUG (BaseJdbcLogger.java:145)- <== Total: 1
同理,模擬用戶id為2的用戶登錄。返回兩條記錄
2019-08-24 14:09:59,006 DEBUG (BaseJdbcLogger.java:145)- ==> Preparing: select * from product where where name like '%iphone%' 2019-08-24 14:09:59,017 DEBUG (BaseJdbcLogger.java:145)- ==> Parameters: 2019-08-24 14:09:59,020 DEBUG (BaseJdbcLogger.java:145)- <== Total: 2
大概的簡易數據權限就這樣了,下面多談談在真實業務場景下的一些情況:
1,不同的授權類型都是在數據庫中進行維護,在不同的實現中,讀取數據庫的權限配置信息,進而封裝sql
2,存在多表關聯的時候,或非驅動表控制了數據權限,驅動表沒有控制,根據不同的業務場景具體分析,對sql的處理也就更加困難了。
3,在分布式中存在跨系統問題的數據權限控制。得看情況,做方案。
感謝各位的閱讀,以上就是“怎么通過MyBatis自定義插件實現簡易數據權限”的內容了,經過本文的學習后,相信大家對怎么通過MyBatis自定義插件實現簡易數據權限這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。