隨筆-11  評(píng)論-16  文章-1  trackbacks-0

          第四章

          細(xì)粒度數(shù)據(jù)查詢權(quán)限

          (上)

           

           

          通過基于角色訪問控制,我們可以控制哪些人具有某種權(quán)限。比如總公司員工柴其貴、分公司員工李朵朵和營業(yè)部員工賈志宏,三個(gè)人都具有訪問“查詢員工”頁面權(quán)限。

          但,由于他們?nèi)怂诠炯?jí)別不同(總公司、分公司和營業(yè)部),進(jìn)入查詢員工頁面,系統(tǒng)展示出來的員工數(shù)據(jù)應(yīng)該是不同的。 

          此類數(shù)據(jù)查詢權(quán)限,在業(yè)務(wù)系統(tǒng)里面隨處可見。畢竟 N 多操作,都起源于查詢。連增加數(shù)據(jù)操作都有,比如增加表單的某個(gè)下拉框內(nèi)容,可能來自數(shù)據(jù)庫查詢。 

          數(shù)據(jù)查詢權(quán)限,包括 2 個(gè)緯度:行級(jí)和列級(jí)。

          現(xiàn)有方案

          常見拼湊 SQL

          常見做法是,采用 if else 做判斷,決定執(zhí)行那條程序分支,也就是 SQL

          String sql=””;
          if( user.getCompanyLevel()==Constants.總公司 ) {
              sql
          =”select * from demouser u, company c where u.companyId=c.id”; //查詢所有員工
          else if( user.getCompanyLevel()==Constants.分公司 ) {
              String currentUserCompanyId
          =user.getCompanyId();
              sql
          =” select * from demouser u, company c where u.companyId=c.id and c.id”= currentUserCompanyId + “ or c.pid=+currentUserCompanyId; //查詢本分公司及下屬營業(yè)部員工
          else if( user.getCompanyLevel()==Constants.營業(yè)部 ) {
              String currentUserCompanyId
          =user.getCompanyId();
              sql
          =” select * from demouser u, company c where u.companyId=c.id and c.id”= currentUserCompanyId; //查詢本營業(yè)部員工
          }

          變通方法

          也有不少開發(fā)者對上述方法做了改進(jìn),我了解到如下改進(jìn)方法:

          1. 采用 AOP 技術(shù),向 find/select 模型注入 where 條件;

          2. SQL 語句全部提取出來,集中保存在某個(gè) SQL 配置文件里面,類似 HIBERNATE 那樣。

           

          上述方法,都不能減少 if else 判斷,只是把 SQL 語句做了轉(zhuǎn)移。 AOP 注入方式,將 if else 判斷從模型層轉(zhuǎn)移到注入層。集中提取 SQL 方式,只是將 SQL 轉(zhuǎn)移到統(tǒng)一的保存文件, if else 依然轉(zhuǎn)移不掉。

           

          關(guān)于列級(jí)控制、分頁查詢和自定義條件查詢,那就更麻煩了,在此不做敘述。

          如果使用 Metadmin

          在設(shè)計(jì) Metadmin 之初,我們確定了這些目標(biāo):

          1. 將行列級(jí)授權(quán)邏輯、 if else 判斷全部從業(yè)務(wù)代碼中剝離出去,達(dá)到權(quán)限與業(yè)務(wù)完全解開耦合;

          2. 提供 API 供業(yè)務(wù)方法調(diào)用,通過該方法獲取該用戶具有權(quán)限查詢的數(shù)據(jù);

          3. 整個(gè)過程不要編碼,也不要 XML ,通過界面設(shè)計(jì)出來,并且每個(gè)查詢邏輯設(shè)計(jì)完畢,可以立即在線測試,保證查詢邏輯無誤。

           

          為此, Metadmin 提供如下服務(wù):

          1. Metadmin 提供數(shù)據(jù)查詢 API :告訴 metadmin ,當(dāng)前是誰想要查什么數(shù)據(jù), metadmin 就能返回該用戶具有權(quán)限查詢的數(shù)據(jù);

          2. Metadmin 提供的 API 支持分頁和自定義條件查詢,當(dāng)然這一切都是在該用戶的授權(quán)范圍內(nèi);

          3. 權(quán)限設(shè)計(jì)器,通過設(shè)計(jì)器展現(xiàn)出業(yè)務(wù)數(shù)據(jù)庫表,運(yùn)用鼠標(biāo)拖拽等操作把查詢邏輯設(shè)計(jì)出來,并可以在線測試;

          4. 支持復(fù)雜、特定數(shù)據(jù)庫邏輯手工輸入 SQL ,調(diào)優(yōu)性能。

           

          以下演示來自 metadmin 下載包里面包含的演示示例,可以在 www.metadmin.com 下載 Metadmin 安裝程序包。

           

          API

          MetadminService 類:

          static QueryResult

          query (int privilegeId, User  user, java.util.Map context) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果。

          static QueryResult

          query (int privilegeId, User  user, java.util.Map context, CustomizedWhere  where) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果。

          static QueryResult

          query (int privilegeId, User  user, java.util.Map context, CustomizedWhere  where, int first, int max) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static QueryResult

          query (int privilegeId, User  user, java.util.Map context, int first, int max) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static int

          queryCount (int privilegeId, User  user, java.util.Map context) 
                    評(píng)估查詢授權(quán)策略,返回匹配記錄的個(gè)數(shù)。

          static int

          queryCount (int privilegeId, User  user, java.util.Map context, CustomizedWhere  where) 
                    評(píng)估查詢授權(quán)策略,返回匹配記錄的個(gè)數(shù)。

           

          WebMetadminService 類,為 WEB 程序定制的類,從 HttpRequest 自動(dòng)讀取當(dāng)前用戶:

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, CustomizedWhere  where) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, CustomizedWhere  where, int first, int max) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, int first, int max) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, java.util.Map context) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, java.util.Map context,CustomizedWhere  where) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, java.util.Map context,CustomizedWhere  where, int first, int max) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static java.util.Collection

          query (HttpServletRequest req, int privilegeId, java.util.Map context, int first, int max) 
                    評(píng)估查詢授權(quán)策略,返回查詢結(jié)果,支持分頁。

          static int

          queryCount (HttpServletRequest req, int privilegeId) 
                    評(píng)估查詢授權(quán)策略,返回匹配記錄的個(gè)數(shù)。

          static int

          queryCount (HttpServletRequest req, int privilegeId, CustomizedWhere  where) 
                    評(píng)估查詢授權(quán)策略,返回匹配記錄的個(gè)數(shù)。

          static int

          queryCount (HttpServletRequest req, int privilegeId, java.util.Map context) 
                    評(píng)估查詢授權(quán)策略,返回匹配記錄的個(gè)數(shù)。

          static int

          queryCount (HttpServletRequest req, int privilegeId, java.util.Map context,CustomizedWhere  where) 
                    評(píng)估查詢授權(quán)策略,返回匹配記錄的個(gè)數(shù)。

           

          業(yè)務(wù)數(shù)據(jù)庫

          第一章講解了 Metadmin 對于數(shù)據(jù)庫的分類:權(quán)限數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù),兩者保存在不同 schema 里面。

          WEB-INF/metadmin/datasources.xml

          <?xml version="1.0"?>
          <datasources>
              
          <datasource name="metadmin" configFile="metadmin.properties"/>
              
          <datasource name="mydemo" configFile="mysql.properties" schemas="mydemo, metadmin"/>
          </datasources>

           

          name=”mydemo” 的數(shù)據(jù)源表示業(yè)務(wù)數(shù)據(jù)源,具體配置信息在 mysql.properties 文件里面,打開設(shè)計(jì)器時(shí),只展示該數(shù)據(jù)庫的 mydemometadmin 兩個(gè) schema 數(shù)據(jù)庫表和視圖。

          具體數(shù)據(jù)源配置信息,參閱: http://www.metadmin.com/doc/main.html#數(shù)據(jù)源 2.6

          數(shù)據(jù)查詢設(shè)計(jì)器

          在打開數(shù)據(jù)查收設(shè)計(jì)器之前,開發(fā)者先準(zhǔn)備好 JavaBean ,也就是打開把查詢出來的數(shù)據(jù)保存到哪個(gè) Java 值對象。演示程序提供了 Employee ,將查詢出來的數(shù)據(jù)保存到該 JavaBean 里面。

          Employee.java

          package org.back.demo;

          import java.util.Date;

          public class Employee {
              
          private int id;
              
          private int companyId;
              
          private int departmentId;
              
          private String loginName;
              
          private String name;
              
          private String password;
              
          private String companyName;
              
          private String departmentName;
              
          private int isManager;
              
          private Date hireDate;
              
          // … get/set methods…
          }

           

          啟動(dòng) web 服務(wù)器,在瀏覽器輸入: http://localhost:8080/mydemo/metadmin/designer

          (假定您發(fā)布的 web contextmydemo ,且服務(wù)器端口是 8080

           

          打開左邊條形框里面的“數(shù)據(jù)查詢”,在樹上右擊,選擇“新增數(shù)據(jù)查詢”。如圖示:

           

          在彈出的框里面輸入相關(guān)信息,如圖示:


          我們先新建總公司用戶查看數(shù)據(jù)的 SQL ,分公司和營業(yè)部用戶查詢 SQL 以及怎樣與業(yè)務(wù)系統(tǒng)集成,由于篇幅關(guān)系,下章講述。

           

          在數(shù)據(jù)查詢樹上,單擊“查詢所有員工”,系統(tǒng)自動(dòng)展現(xiàn)數(shù)據(jù)查詢設(shè)計(jì)器。

          然后按照如下步驟操作:

          1.  展開 mydemo schema ,展開表;

          2.  雙擊 company, department, demouser 表,因?yàn)橐樵冞@三張表;

          3.  勾選 companyname 字段, departmentname 字段,勾選 demouser 表所有字段;

          4.  在映射類里面,輸入 org.back.demo.Employee

          5.  檢查下面的字段映射是否有誤,修改 company 表的 name 映射屬性為 companyName ,修改 department 表的 name 映射屬性為 departmentName

          如圖示: 

          到此,設(shè)計(jì)還差一個(gè)步驟,設(shè)置 where 條件。本查詢 where 條件是 3 張表關(guān)聯(lián)。

          按照如下步驟操作:

          1.  點(diǎn)擊設(shè)計(jì)器下方的“ WHERE ”標(biāo)簽頁

          2.  右擊條件組,選擇“新增二元條件”;

          3.  點(diǎn)擊第一個(gè)字段節(jié)點(diǎn),在右邊選擇“ company.id ”也就是 company 表的 id 字段;

          4.  然后,設(shè)置第二個(gè)字段為“ demouser.companyId ”字段;

          5.  右擊條件組,選擇“新增二元條件”;

          6.    將第一個(gè)字段選擇為“ department.id ”,第二個(gè)字段選擇為“ demouser.departmentId ”。

          至此,三表關(guān)聯(lián)完畢。也就是完成 SQL company.id=demouser.companyId and department.id=demouser.departmentId

          如圖示:

           

          現(xiàn)在,我們可以測試了!選擇設(shè)計(jì)器下方“測試”標(biāo)簽頁,點(diǎn)擊控制臺(tái)執(zhí)行小圖標(biāo)。 Metadmin 將顯示該 sql 語句能查詢的數(shù)據(jù),行列級(jí)!

          如圖示:

          至此,我們完全放心該 SQL 語句沒有任何問題。點(diǎn)擊“保存”圖標(biāo),保存設(shè)計(jì)結(jié)果。 

          下章,講解其他 SQL 還有怎樣與業(yè)務(wù)系統(tǒng)集成。

          posted on 2009-06-19 11:52 細(xì)粒度權(quán)限管理 閱讀(2392) 評(píng)論(2)  編輯  收藏

          評(píng)論:
          # re: 《玩轉(zhuǎn)細(xì)粒度權(quán)限管理》 四,細(xì)粒度數(shù)據(jù)查詢權(quán)限(上) 2009-06-19 12:16 | 找個(gè)美女做老婆
          不錯(cuò)不錯(cuò),收藏了
          Java樂園 技術(shù)交流社區(qū):http://www.javaly.cn
          Java樂園 群號(hào):15651281
          驗(yàn)證消息 : Java樂園  回復(fù)  更多評(píng)論
            
          # re: 《玩轉(zhuǎn)細(xì)粒度權(quán)限管理》 四,細(xì)粒度數(shù)據(jù)查詢權(quán)限(上) 2009-06-19 12:17 | 找個(gè)美女做老婆
          能把原代碼共享出來嗎?

          Java樂園 技術(shù)交流社區(qū):http://www.javaly.cn
          Java樂園 群號(hào):15651281
          驗(yàn)證消息 : Java樂園  回復(fù)  更多評(píng)論
            

          只有注冊用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 民乐县| 高青县| 和平县| 普兰县| 柘荣县| 娄烦县| 丁青县| 托里县| 永和县| 漯河市| 孟村| 秭归县| 拉萨市| 阳山县| 南郑县| 兴安县| 昌都县| 东山县| 沛县| 汉阴县| 灌南县| 平利县| 余姚市| 奉新县| 丰台区| 贵港市| 乡宁县| 夏邑县| 阿勒泰市| 宁阳县| 石景山区| 靖江市| 文昌市| 陇南市| 正定县| 黄浦区| 玉溪市| 马关县| 开阳县| 南江县| 万源市|