<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    小菜毛毛技術分享

    與大家共同成長

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      164 Posts :: 141 Stories :: 94 Comments :: 0 Trackbacks

    #

    1)JSON簡介
    2)JSON/LIST轉換
    3)JSON/MAP轉換
    4)JSON/動態Bean轉換
    5)JSON/靜態Bean轉換
    6)JSON/XML輸出

    1.JSON簡介
    JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式,基于JavaScript,但是不僅僅限于此。
    詳情可以參考www.json.org
    例如一段XML
    <?xml version="1.0" encoding="utf-8"?>
     <shop>
      <name>飯店</name>
        <city>北京</city>
     </shop>
    用JSON表示如下:
    {
      "name":"飯店",
      "city":"北京"
    }
    XML的解析得考慮子節點父節點關系,而JSON的解析難度相當低,很多控件,尤其是ajax相關的數據交換很多都用json.

    2)JSON/LIST轉換
    本教程解析采用的json-lib,官方網站為http://json-lib.sourceforge.net/,本教程參考官方教程
    環境需要配置的jar如下
    commons-beanutils和ezmorph控制反射
    commons-collections是apachecommons的子項目,擴展了java集合類
    commons-lang擴展了java.lang包
    commons-logging日志類
    xom是xml解析類,可以參考www.xom.nu
    junit單元測試用的jar
    json-lib核心jar
    項目文件夾中擁有貨物參數(Shop)和貨物參數列表(ShopList)兩個實體
    Shop包含name和property兩個字段,ShopList包含Shop的列表
    對應的json是
    String s = "[{name:'重量',property:'p1'},{name:'尺寸',property:'p2'},{name:'顯卡類型',property:'p3'},{name:'硬盤容量',property:'p4'},{name:'處理器',property:'p5'},{name:'內存',property:'p6'},{name:'型號',property:'p7'},{name:'貨號',property:'p8'},{name:'品牌',property:'p9'}]";
    把這樣的數據結構作為用戶定義個人信息存入數據庫可以達到個性化參數的作用,
    比如shopex的數據庫中很多表就是用的json數據類型。因為用戶自己添加的參數的長度是不固定的
    比如上述例子就擁有9個用戶自定義的參數
    當用戶需要填寫這些參數的時候,需要轉化為list,然后在struts2的view去顯示
    完成的代碼可以參考附件的ArrayUtil文件
    核心代碼僅僅就一行JSONArray jsonArray = JSONArray.fromObject(s);
    得到這個jsonArray后要轉化為ArrayList,需要用循環遍歷,如下
    for (int i = 0; i < jsonArray.size(); i++) {
       Object o = jsonArray.get(i);
       JSONObject jsonObject = JSONObject.fromObject(o);
       Shop Person = (Shop) JSONObject.toBean(jsonObject, Shop.class);
       list.add(Person);
    }
    然后得到的list就是普通的ArrayList了

    3)JSON/MAP轉換
    當我們初始化完一個map,放入json可以直接放入
    Map<String, String> map = new HashMap<String, String>();
    map.put("name", "重量");
    map.put("property", "p1");
    JSONObject jsonObject = JSONObject.fromObject(map);
    核心代碼為
    JSONObject jsonObject = JSONObject.fromObject(map);
    JsonLib會自動映射
    完成例子見附件MapUtil.java


    4)JSON/動態Bean轉換
    所謂動態bean即是java運行的時候根據情況創建的,而不是程序員已經好了的Bean
    JsonLib會自動根據Json格式數據創建字段,然后創建一個包含這些字段的Object
    本例子中采用JUNIT做單元測試驗證,見DynamicBean.java
    String s = "{name:'重量',property:'p1'}";
    JSONObject jsonObject = JSONObject.fromObject(s);
    Object bean = JSONObject.toBean(jsonObject);
    assertEquals(jsonObject.get("name"), PropertyUtils.getProperty(bean,"name"));
    assertEquals(jsonObject.get("property"), PropertyUtils.getProperty(bean,"property"));


    5)JSON/靜態Bean轉換(StaticBean.java)
    JSONLIB在轉換的時候會自動查找關系,比如子類和父類
    例如JSON數據源
    String s = "{'shopList':[{name:'重量',property:'p1'},{name:'尺寸',property:'p2'},{name:'顯卡類型',property:'p3'},{name:'硬盤容量',property:'p4'},{name:'處理器',property:'p5'},{name:'內存',property:'p6'},{name:'型號',property:'p7'},{name:'貨號',property:'p8'},{name:'品牌',property:'p9'}]}";
    存入Map
    map.put("shopList", Shop.class);
    ShopList shopList = (ShopList) JSONObject.toBean(JSONObject.fromObject(s), ShopList.class, map);
    JSONObject.toBean()方法的三個參數分別表示數據源對應的JSON對象,轉化后的對象ShopList和數據源map
    然后這樣也可以取得ShopList
    這種方法和動態轉換的區別在于,動態轉換僅僅只是轉為Object
    而靜態轉換是轉換為已經定義過的實體類,會自動映射(這點類似Ibatis)

    6)JSON/XML輸出
    如果自己用String的方法轉化為XML輸出要寫很多代碼,然后條用JSONLIB,核心代碼僅僅一步
    String xmlObject = xmlSerializer.write(object);
    比如
    String s = "{name:'重量',property:'p1'}";
    XMLSerializer xmlSerializer = new XMLSerializer();
    JSONObject object = JSONObject.fromObject(s);
    String xmlObject = xmlSerializer.write(object);
    System.out.println(xmlObject);

    輸出結果為
    <?xml version="1.0" encoding="UTF-8"?>
    <o>
      <name type="string">重量</name>
      <property type="string">p1</property>
    </o>



    posted @ 2009-08-29 00:39 小菜毛毛 閱讀(2446) | 評論 (1)編輯 收藏

    Java EE應用的性能問題對嚴肅的項目和產品來說是一個非常重要的問題。特別是企業級的應用,并發用戶多,數據傳輸量大,業務邏輯復雜,占用系統資源多,因此性能問題在企業級應用變得至關重要,它和系統的穩定性有著直接的聯系。更加重要的是,性能好的應用在完成相同任務的條件下,能夠占用更少的資源,獲得更好的用戶體驗,換句話說,就是能夠節省費用和消耗,獲得更高的利潤。

    要獲得更好的性能,就需要對原來的系統進行性能調優。對運行在Glassfish上的JavaEE應用,調優是一件相對復雜的事情。在調優以前必須要認識到:對JavaEE的系統,調優是多層次的。一個JavaEE的應用其實是整個系統中很少的一部分。開發人員所開發的JavaEE程序,無論是JSP還是 EJB,都是運行在JavaEE應用服務器(Glassfish)之上。而應用服務器本身也是Java語言編寫的,需要運行在Java虛擬機之上。 Java虛擬機也只不過是操作系統的一個應用而已,和其他的應用(如Apache)對于操作系統來說沒有本質的區別。而操作系統卻運行在一定的硬件環境中,包括CPU,內存,網卡和硬盤等等。在這么多的層次中,每一個層次的因素都會影響整個系統的性能。因此,對一個系統的調優,事實上需要同時對每個層次都要調優。JavaEE應用性能調優不僅僅和Glassfish有關,Java語言有關,還要和操作系統以及硬件都有關系,需要調優者有綜合的知識和技能。這些不同層面的方法需要綜合縱效,結合在一起靈活使用,才能快速有效的定位性能瓶頸。下面是一些具體的案例分析:

     

    內存泄漏問題

            某個JavaEE應用運行在8顆CPU的服務器上。上線運行發現性能不穩定。性能隨著時間的增加而越來越慢。通過操作系統的工具(mpstat),發現在系統很慢的時候,只有一顆CPU很忙,其他的CPU都很空閑。因此懷疑是Java虛擬機經常進行內存回收,因為虛擬機在內存回收的時候,有的回收算法通常只能運行在一個CPU上。通過Java虛擬機的工具“jstat”可以清楚的看到,Java虛擬機進行內存回收的頻率非常高,幾乎每5秒中就有一次,每次回收的時間為2秒鐘。另外,通過“jstat”的輸出還發現每次回收釋放的內存非常有限,大多數對象都無法回收。這種現象很大程度上暗示著內存泄漏。使用 Java虛擬機的工具“jmap”來獲得當前的一個內存映象。發現有很多(超過10000)個的session對象。這是不正常的一個現象。一般來說, session對應于一個用戶的多次訪問,當用戶退出的時候,session就應該失效,對象應該被回收。當我們和這個系統的開發工程師了解有關 session的設置,發現當他們部署應用的時候,竟然將session的timeout時間設置為50分鐘,并且沒有提供logout的接口。這樣的設置下,每個session的數據都會保存50分鐘才會被回收。根據我們的建議,系統提供了logout的鏈接,并且告訴用戶如果退出應用,應該點擊這個 logout的鏈接;并且將session的timeout時間修改為5分鐘。通過幾天的測試,證明泄漏的問題得到解決。

     

    數據庫連接池問題

            某財務應用運行在JavaEE服務器上,后臺連接Oracle數據庫。并發用戶數量超過100人左右的時候系統停止響應。通過操作系統層面的進程監控工具發現進程并沒有被殺死或掛起,而CPU使用率幾乎為零。那么是什么原因導致系統停止響應用戶請求呢?我們利用Java虛擬機的工具(kill -3 pid)將當前的所有線程狀態DUMP出來,發現JavaEE服務器的大部分處理線程都在等待數據庫連接池的連接,而那些已經獲得數據庫連接的線程卻處于阻塞狀態。數據庫管理員應要求檢查了數據庫的狀態,發現所有的連接的session都處于死鎖狀態。顯然,這是因為數據庫端出現了死鎖的操作,阻塞了那些有數據庫操作的請求,占用了所有數據庫連接池中的連接。后續的請求如果還要從連接池中獲取連接,就會阻塞在連接池上。當解決數據庫死鎖的問題之后,性能問題迎刃而解。

     

    大對象緩存問題

            電信應用運行在64位Java虛擬機上,系統運行得很不穩定,系統經常停止響應。使用進程工具查看,發現進程并沒有被殺死或掛起。利用Java虛擬機的工具發現系統在長時間的進行內存回收,內存回收的時間長達15分鐘,整個系統在內存回收的時候就像掛起一樣。另外還觀察到系統使用了12G的內存(因為是 64位虛擬機所以突破了4G內存的限制)。從開發人員那里了解到,這個應用為了提高性能,大量使用了對象緩存,但是事與愿違,在Java中使用過多的內存,雖然在正常運行的時候能夠獲得很好的性能,但是會大大增加內存回收的時間。特別是對象緩存,本系統使用了8G的緩存空間,共緩存了6000多萬個對象,對這些對象的遍歷導致了長時間的內存回收。根據我們的建議,將緩存空間減少到1G,并調整回收算法(使用增量回收的算法),使得系統由于內存回收而造成的最大停頓時間減少到4秒,基本滿足用戶的需求。


    外部命令問題

            數字校園應用運行在4CPU的Solaris10服務器上,中間件為JavaEE服務器。系統在做大并發壓力測試的時候,請求響應時間比較慢,通過操作系統的工具(mpstat)發現CPU使用率比較高。并且系統占用絕大多數的CPU資源而不是應用本身。這是個不正常的現象,通常情況下用戶應用的CPU占用率應該占主要地位,才能說明系統是正常工作。通過Solaris 10的Dtrace腳本,我們查看當前情況下哪些系統調用花費了最多的CPU資源,竟然發現最花費CPU的系統調用是“fork”。眾所周知, “fork”系統調用是用來產生新的進程,在Java虛擬機中只有線程的概念,絕不會有進程的產生。這是個非常異常的現象。通過本系統的開發人員,我們找到了答案:每個用戶請求的處理都包含執行一個外部shell腳本,來獲得系統的一些信息。這是通過Java的“Runtime.getRuntime ().exec”來完成的,但是這種方法在Java中非常消耗資源。Java虛擬機執行這個命令的方式是:首先克隆一個和當前虛擬機一樣的進程,再用這個新的進程去執行外部命令,最后再退出這個進程。如果頻繁執行這個操作,系統的消耗會很大,不僅在CPU,內存操作也很重。用戶根據建議去掉這個shell 腳本執行的語句,系統立刻回復了正常。


    文件操作問題

            內容管理(CMS)系統運行在JavaEE服務器上,當系統長時間運行以后,性能非常差,用戶請求的延時比系統剛上線的時候要大很多,并且用戶的并發量很小,甚至是單個用戶也很慢。通過操作系統的工具觀察,一切都很正常,CPU利用率不高,IO也不是很大,內存很富余,網絡幾乎沒有壓力(因為并發用戶少)。先不考慮線程互鎖的問題,因為單個用戶性能也不好。通過Java虛擬機觀察也沒有發現什么問題(內存回收很少發生)。這使得我們不得不使用代碼跟蹤器來全程跟蹤代碼。我們采用了Netbeans的Profiler,跟蹤的結果非常意外,用戶請求的90%的時間在創建新文件。從系統設計人員了解到,此系統使用了一個目錄用于保存所有上傳和共享的文件,文件用其命名方式來唯一區別于其他文件。我們查看了那個文件目錄,發現該目錄下已經擁有80萬個文件了。這時候我們才定位到問題了:在同個目錄下放置太多的文件,在創建新文件的時候,系統的開銷是比較大的,例如為了防止重名,文件系統會遍歷當前目錄下所有的文件名等等。根據我們的建議,將文件分類保存在不同的目錄下,性能有了大幅度的提高。


    高速緩存命中率問題

            運行在JavaEE服務器上的ERP系統,在CPU充分利用的情況下性能仍然不太好。從操作系統層面上觀察不到什么大問題,而且ERP系統過于復雜,代碼跟蹤比較困難。于是進行了CPU狀態的進一步檢查,發現CPU的TLB命中率不是很高,于是對Java虛擬機的啟動參數進行了修改,強迫虛擬機使用大尺寸的內存頁面,提高TLB的命中率。下面的參數是在Sun的HOTSPOT中調整大尺寸(4M)頁面的設置:
    -XX:+AggressiveHeap
    -XX:LargePageSizeInBytes=256m
    通過調整,TLB命中明顯提高,性能也得到近40%的提升。


    轉載之:http://developers.sun.com.cn/blog/yutoujava/entry/8

    posted @ 2009-08-29 00:30 小菜毛毛 閱讀(332) | 評論 (0)編輯 收藏

    1.使用DNS輪詢.
    2.使用Apache R-proxy方式。
    3.使用Apache mod_jk方式.
     
    DNS輪詢的缺點是,當集群中某臺服務器停止之后,用戶由于dns緩存的緣故,便無法訪問服務,
    必須等到dns解析更新,或者這臺服務器重新啟動。
    還有就是必須把集群中的所有服務端口暴露給外界,沒有用apache做前置代理的方式安全,
    并且占用大量公網IP地址,而且tomcat還要負責處理靜態網頁資源,影響效率。
    優點是集群配置最簡單,dns設置也非常簡單。
     
    R-proxy的缺點是,當其中一臺tomcat停止運行的時候,apache仍然會轉發請求過去,導致502網關錯誤。
    但是只要服務器再啟動就不存在這個問題。
     
    mod_jk方式的優點是,Apache 會自動檢測到停止掉的tomcat,然后不再發請求過去。
    缺點就是,當停止掉的tomcat服務器再次啟動的時候,Apache檢測不到,仍然不會轉發請求過去。
     
    R-proxy和mod_jk的共同優點是.可以只將Apache置于公網,節省公網IP地址資源。
    可以通過設置來實現Apache專門負責處理靜態網頁,讓Tomcat專門負責處理jsp和servlet等動態請求。
    共同缺點是:如果前置Apache代理服務器停止運行,所有集群服務將無法對外提供。
    R-proxy和mod_jk對靜態頁面請求的處理,都可以通設置來選取一個盡可能優化的效果。
    這三種方式對實現最佳負載均衡都有一定不足,mod_jk相對好些,可以通過設置lbfactor參數來分配請求任務,但又因為mod_jk2方式不被推薦,mod_jk2已經不再被更新了。郁悶中……
    posted @ 2009-08-29 00:29 小菜毛毛 閱讀(608) | 評論 (0)編輯 收藏

    為應用程序添加搜索能力經常是一個常見的需求。本文介紹了一個框架,開發者可以使用它以最小的付出實現搜索引擎功能,理想情況下只需要一個配置文件。該框架基于若干開源的庫和工具,如 Apache Lucene,Spring 框架,cpdetector 等。它支持多種資源。其中兩個典型的例子是數據庫資源和文件系統資源。Indexer 對配置的資源進行索引并傳輸到中央服務器,之后這些索引可以通過 API 進行搜索。Spring 風格的配置文件允許清晰靈活的自定義和調整。核心 API 也提供了可擴展的接口。
    引言

    為應用程序添加搜索能力經常是一個常見的需求。盡管已經有若干程序庫提供了對搜索基礎設施的支持,然而對于很多人而言,使用它們從頭開始建立一個搜索引擎將是一個付出不小而且可能乏味的過程。另一方面,很多的小型應用對于搜索功能的需求和應用場景具有很大的相似性。本文試圖以對多數小型應用的適用性為出發點,用 Java 語言構建一個靈活的搜索引擎框架。使用這個框架,多數情形下可以以最小的付出建立起一個搜索引擎。最理想的情況下,甚至只需要一個配置文件。特殊的情形下,可以通過靈活地對框架進行擴展滿足需求。當然,如題所述,這都是借助開源工具的力量。


    基礎知識

    Apache Lucene 是開發搜索類應用程序時最常用的 Java 類庫,我們的框架也將基于它。為了下文更好的描述,我們需要先了解一些有關 Lucene 和搜索的基礎知識。注意,本文不關注索引的文件格式、分詞技術等話題。

    什么是搜索和索引

    從用戶的角度來看,搜索的過程是通過關鍵字在某種資源中尋找特定的內容的過程。而從計算機的角度來看,實現這個過程可以有兩種辦法。一是對所有資源逐個與關鍵字匹配,返回所有滿足匹配的內容;二是如同字典一樣事先建立一個對應表,把關鍵字與資源的內容對應起來,搜索時直接查找這個表即可。顯而易見,第二個辦法效率要高得多。建立這個對應表事實上就是建立逆向索引(inverted index)的過程。
    Lucene 基本概念

    Lucene 是 Doug Cutting 用 Java 開發的用于全文搜索的工具庫。在這里,我假設讀者對其已有基本的了解,我們只對一些重要的概念簡要介紹。要深入了解可以參考 參考資源 中列出的相關文章和圖書。下面這些是 Lucene 里比較重要的類。
    Document:索引包含多個 Document。而每個 Document 則包含多個 Field 對象。Document 可以是從數據庫表里取出的一堆數據,可以是一個文件,也可以是一個網頁等。注意,它不等同于文件系統中的文件。
    Field:一個 Field 有一個名稱,它對應 Document的一部分數據,表示文檔的內容或者文檔的元數據(與下文中提到的資源元數據不是一個概念)。一個 Field 對象有兩個重要屬性:Store ( 可以有 YES, NO, COMPACT 三種取值 ) 和 Index ( 可以有 TOKENIZED, UN_TOKENIZED, NO, NO_NORMS 四種取值 )
    Query:抽象了搜索時使用的語句。
    IndexSearcher:提供Query對象給它,它利用已有的索引進行搜索并返回搜索結果。
    Hits:一個容器,包含了指向一部分搜索結果的指針。
    使用 Lucene 來進行編制索引的過程大致為:將輸入的數據源統一為字符串或者文本流的形式,然后從數據源提取數據,創建合適的 Field 添加到對應該數據源的 Document 對象之中。


    系統概覽

    要建立一個通用的框架,必須對不同情況的共性進行抽象。反映到設計需要注意兩點。一是要提供擴展接口;二是要盡量降低模塊之間的耦合程度。我們的框架很簡單地分為兩個模塊:索引模塊和搜索模塊。索引模塊在不同的機器上各自進行對資源的索引,并把索引文件(事實上,下面我們會說到,還有元數據)統一傳輸到同一個地方(可以是在遠程服務器上,也可以是在本地)。搜索模塊則利用這些從多個索引模塊收集到的數據完成用戶的搜索請求。

    圖 1 展現了整體的框架??梢钥吹?,兩個模塊之間相對是獨立的,它們之間的關聯不是通過代碼,而是通過索引和元數據。在下文中,我們將會詳細介紹如何基于開源工具設計和實現這兩個模塊。


    圖 1. 系統架構圖


    建立索引

    可以進行索引的對象有很多,如文件、網頁、RSS Feed 等。在我們的框架中,我們定義可以進行索引的一類對象為資源。從實現細節上來說,從一個資源中可以提取出多個 Document 對象。文件系統資源和數據庫結果集資源都是資源的代表性例子。

    前面提到,從資源中收集到的索引被統一傳送到同一個地方,以被搜索模塊所用。顯然除了索引之外,搜索模塊需要有對資源更多的了解,如資源的名稱、搜索該資源后搜索結果的呈現格式等。這些額外的附加信息稱為資源的元數據。元數據和索引數據一同被收集起來,放置到某個特定的位置。

    簡要地介紹過資源的概念之后,我們首先為其定義一個 Resource 接口。這個接口的聲明如下。


    清單 1. Resource 接口
    public interface Resource {
    // RequestProcessor 對象被動地從資源中提取 Document,并返回提取的數量
    public int extractDocuments(ResourceProcessor processor);

    // 添加的 DocumentListener 將在每一個 Document 對象被提取出時被調用
    public void addDocumentListener(DocumentListener l);

    // 返回資源的元數據
    public ResourceMetaData getMetaData();
    }


    其中元數據包含的字段見下表。在下文中,我們還會對元數據的用途做更多的介紹。


    表 1. 資源元數據包含的字段
    屬性 類型 含義
    resourceName String 資源的唯一名稱
    resourceDescription String 資源的介紹性文字
    hitTextPattern String 當文檔被搜索到時,這個 pattern 規定了結果顯示的格式
    searchableFields String[] 可以被搜索的字段名稱

    而 DocumentListener 的代碼如下。


    清單 2. DocumentListener 接口
    public interface DocumentListener extends EventListener {
    public void documentExtracted(Document doc);
    }



    為了讓索引模塊能夠知道所有需要被索引的資源,我們在這里使用 Spring 風格的 XML 文件配置索引模塊中的所有組件,尤其是所有資源。您可以在 下載部分 查看一個示例配置文件。

    為什么選擇使用 Spring 風格的配置文件?

    這主要有兩個好處:

    僅依賴于 Spring Core 和 Spring Beans 便免去了定義配置機制和解析配置文件的負擔;
    Spring 的 IoC 機制降低了框架的耦合性,并使擴展框架變得簡單;



    基于以上內容,我們可以大致描述出索引模塊工作的過程:

    首先在 XML 配置的 bean 中找出所有 Resource 對象;
    對每一個調用其 extractDocuments() 方法,這一步除了完成對資源的索引外,還會在每次提取出一個 Document 對象之后,通知注冊在該資源上的所有 DocumentListener;
    接著處理資源的元數據(getMetaData() 的返回值);
    將緩存里的數據寫入到本地磁盤或者傳送給遠程服務器;

    在這個過程中,有兩個地方值得注意。

    第一,對資源可以注冊 DocumentListener 使得我們可以在運行時刻對索引過程有更為動態的控制。舉一個簡單例子,對某個文章發布站點的文章進行索引時,一個很正常的要求便是發布時間更靠近當前時間的文章需要在搜索結果中排在靠前的位置。每篇文章顯然對應一個 Document 對象,在 Lucene 中我們可以通過設置 Document 的 boost 值來對其進行加權。假設其中文章發布時間的 Field 的名稱為 PUB_TIME,那么我們可以為資源注冊一個 DocumentListener,當它被通知時,則檢測 PUB_TIME 的值,根據距離當前時間的遠近進行加權。

    第二點很顯然,在這個過程中,extractDocuments() 方法的實現依不同類型的資源而各異。下面我們主要討論兩種類型的資源:文件系統資源和數據庫結果集資源。這兩個類都實現了上面的 接口。

    文件系統資源

    對文件系統資源的索引通常從一個基目錄開始,遞歸處理每個需要進行索引的文件。該資源有一個字符串數組類型的 excludedFiles 屬性,表示在處理文件時需要排除的文件絕對路徑的正則表達式。在遞歸遍歷文件系統樹的同時,絕對路徑匹配 excludedFiles 中任意一項的文件將不會被處理。這主要是考慮到一般我們只需要對一部分文件夾(比如排除可能存在的備份目錄)中的一部分文件(如 doc, ppt 文件等)進行索引。

    除了所有文件共有的文件名、文件路徑、文件大小和修改時間等 Field,不同類型的文件需要有不同的處理方法。為了保留靈活性,我們使用 Strategy 模式封裝對不同類型文件的處理方式。為此我們抽象出一個 DocumentBuilder 的接口,該接口僅定義了一個方法如下:


    清單 3. DocumentBuilder 接口
    public interface DocumentBuilder {
    Document buildDocument(InputStream is);
    }

    什么是 Strategy 模式?

    根據 Design patterns: Elements of reusable object orientated software 一書:Strategy 模式“定義一系列的算法,把它們分別封裝起來,并且使它們相互可以替換。這個模式使得算法可以獨立于使用它的客戶而變化。”


    不同的 DocumentBuilder(Strategy) 用于從一個輸入流中讀取數據,處理不同類型的文件。對于常見的文件格式來說,都有合適的開源工具幫助進行解析。在下表中我們列舉一些常見文件類型的解析辦法。

    文件類型 常用擴展名 可以使用的解析辦法
    純文本文檔 txt 無需類庫解析
    RTF 文檔 rtf 使用 javax.swing.text.rtf.RTFEditorKit 類
    Word 文檔(非 OOXML 格式) doc Apache POI (可配合使用 POI Scratchpad)
    PowerPoint 演示文稿(非 OOXML 格式) xls Apache POI (可配合使用 POI Scratchpad)
    PDF 文檔 pdf PDFBox(可能中文支持欠佳)
    HTML 文檔 htm, html JTidy, Cobra

    這里以 Word 文件為例,給出一個簡單的參考實現。


    清單 4. 解析純文本內容的實現
    // WordDocument 是 Apache POI Scratchpad 中的一個類
    Document buildDocument(InputStream is) {
    String bodyText = null;
    try {
    WordDocument wordDoc = new WordDocument(is);
    StringWriter sw = new StringWriter();
    wordDoc.writeAllText(sw);
    sw.close();
    bodyText = sw.toString();
    } catch (Exception e) {
    throw new DocumentHandlerException("Cannot extract text from a Word document", e);
    }
    if ((bodyText != null) && (bodyText.trim().length() > 0)) {
    Document doc = new Document();
    doc.add(new Field("body", bodyText, Field.Store.YES, Field.Index.TOKENIZED));
    return doc;
    }
    return null;
    }



    那么如何選擇合適的 Strategy 來處理文件呢?UNIX 系統下的 file(1) 工具提供了從 magicnumber 獲取文件類型的功能,我們可以使用 Runtime.exec() 方法調用這一命令。但這需要在有 file(1) 命令的情況下,而且并不能識別出所有文件類型。在一般的情況下我們可以簡單地根據擴展名來使用合適的類處理文件。擴展名和類的映射關系寫在 properties 文件中。當需要添加對新的文件類型的支持時,我們只需添加一個新的實現 DocumentBuilder 接口的類,并在映射文件中添加一個映射關系即可。

    數據庫結果集資源

    大多數應用使用數據庫作為永久存儲,對數據庫查詢結果集索引是一個常見需求。

    生成一個數據庫結果集資源的實例需要先提供一個查詢語句,然后執行查詢,得到一個結果集。這個結果集中的內容便是我們需要進行索引的對象。extractDocuments 的實現便是為結果集中的每一行創建一個 Document 對象。和文件系統資源不同的是,數據庫資源需要放入 Document 中的 Field 一般都存在在查詢結果集之中。比如一個簡單的文章發布站點,對其后臺數據庫執行查詢 SELECT ID, TITLE, CONTENT FROM ARTICLE 返回一個有三列的結果集。對結果集的每一行都會被提取出一個 Document 對象,其中包含三個 Field,分別對應這三列。

    然而不同 Field 的類型是不同的。比如 ID 字段一般對應 Store.YES 和 Index.NO 的 Field;而 TITLE 字段則一般對應 Store.YES 和 Index.TOKENIZED 的 Field。為了解決這個問題,我們在數據庫結果集資源的實現中提供一個類型為 Properties 的 fieldTypeMappings 屬性,用于設置數據庫字段所對應的 Field 的類型。對于前面的情況來說,這個屬性可能會被配置成類似這樣的形式:

    ID = YES, NO
    TITLE = YES, TOKENIZED
    CONTENT = NO, TOKENIZED


    配合這個映射,我們便可以生成合適類型的 Field,完成對結果集索引的工作。


    收集索引

    完成對資源的索引之后,還需要讓索引為搜索模塊所用。前面我們已經說過這里介紹的框架主要用于小型應用,考慮到復雜性,我們采取簡單地將分布在各個機器上的索引匯總到一個地方的策略。

    匯總索引的傳輸方式可以有很多方案,比如使用 FTP、HTTP、rsync 等。甚至索引模塊和搜索模塊可以位于同一臺機器上,這種情況下只需要將索引進行本地拷貝即可。同前面類似,我們定義一個 Transporter 接口。


    清單 5. Transporter 接口
    public interface Transporter {
    public void transport(File file);
    }


    以 FTP 方式傳輸為例,我們使用 Commons Net 完成傳輸的操作。

    public void transport(File file) throws TransportException {
    FTPClient client = new FTPClient();
    client.connect(host);
    client.login(username, password);
    client.changeWorkingDirectory(remotePath);
    transportRecursive(client, file);
    client.disconnect();
    }

    public void transportRecursive(FTPClient client, File file) {
    if (file.isFile() && file.canRead()) {
    client.storeFile(file.getName(), new FileInputStream(file));
    } else if (file.isDirectory()) {
    client.makeDirectory(file.getName());
    client.changeWorkingDirectory(file.getName());
    File[] fileList = file.listFiles();
    for (File f : fileList) {
    transportRecursive(client, f);
    }
    }
    }



    對其他傳輸方案也有各自的方案進行處理,具體使用哪個 Transporter 的實現被配置在 Spring 風格的索引模塊配置文件中。傳輸的方式是靈活的。比如當需要強調安全性時,我們可以換用基于 SSL 的 FTP 進行傳輸。所需要做的只是開發一個使用 FTP over SSL 的 Transporter 實現,并在配置文件中更改 Transporter 的實現即可。

    進行搜索

    在做了這么多之后,我們開始接觸和用戶關聯最為緊密的搜索模塊。注意,我們的框架不包括一個基于已經收集好的索引進行搜索是個很簡單的過程。Lucene 已經提供了功能強大的 IndexSearcher 及其子類。在這個部分,我們不會再介紹如何使用這些類,而是關注在前文提到過的資源元數據上。元數據從各個資源所在的文件夾中讀取得到,它在搜索模塊中扮演重要的角色。

    構建一個查詢

    對不同資源進行搜索的查詢方法并不一樣。例如搜索一個論壇里的所有留言時,我們關注的一般是留言的標題、作者和內容;而當搜索一個 FTP 站點時,我們更多關注的是文件名和文件內容。另一方面,我們有時可能會使用一個查詢去搜索多個資源的結果。這正是之前我們在前面所提到的元數據中 searchableFields 和 resourceName 屬性的作用。前者指出一個資源中哪些字段是參與搜索的;后者則用于在搜索時確定使用哪個或者哪些索引。從技術細節來說,只有有了這些信息,我們才可以構造出可用的 Query 對象。

    呈現搜索結果

    當從 IndexSearcher 對象得到搜索結果(Hits)之后,當然我們可以直接從中獲取需要的值,再格式化予以輸出。但一來格式化輸出搜索結果(尤其在 Web 應用中)是個很常見的需求,可能會經常變更;二來結果的呈現格式應該是由分散的資源各自定義,而不是交由搜索模塊來定義?;谏厦鎯蓚€原因,我們的框架將使用在資源收集端配置結果輸出格式的方式。這個格式由資源元數據中的 hitTextPattern 屬性定義。該屬性是一個字符串類型的值,支持兩種語法

    形如 ${field_name} 的子字符串都會被動態替換成查詢結果中各個 Document 內 Field 的值。
    形如 $function(...) 的被解釋為函數,括號內以逗號隔開的符號都被解釋成參數,函數可以嵌套。
    例如搜索“具體”返回的搜索結果中包含一個 Document 對象,其 Field 如下表:

    Field 名稱 Field 內容
    url http://example.org/article/1.html
    title 示例標題
    content 這里是具體的內容。

    那么如果 hitTextPatten 被設置為“${title}
    $highlight(${content}, 5, "", "")”,返回的結果經瀏覽器解釋后可能的顯示結果如下(這只是個演示鏈接,請不要點擊):

    示例標題
    這里是具體...

    上面提到的 $highlight() 函數用于在搜索結果中取得最匹配的一段文本,并高亮顯示搜索時使用的短語,其第一個參數是高亮顯示的文本,第二個參數是顯示的文本長度,第三和第四個參數是高亮文本時使用的前綴和后綴。

    可以使用正則表達式和文本解析來實現前面所提到的語法。我們也可以使用 JavaCC 定義 hitTextPattern 的文法,進而生成詞法分析器和語法解析器。這是更為系統并且相對而言不易出錯的方法。對 JavaCC 的介紹不是本文的重點,您可以在下面的 閱讀資源 中找到學習資料。

    下面列出的是一些與我們所提出的框架所相關或者類似的產品,您可以在 學習資料 中更多地了解他們。

    IBM?OmniFind?Family

    OmniFind 是 IBM 公司推出的企業級搜索解決方案?;?UIMA (Unstructured Information Management Architecture) 技術,它提供了強大的索引和獲取信息功能,支持巨大數量、多種類型的文檔資源(無論是結構化還是非結構化),并為 Lotus?Domino?和 WebSphere?Portal 專門進行了優化。

    Apache Solr

    Solr 是 Apache 的一個企業級的全文檢索項目,實現了一個基于 HTTP 的搜索服務器,支持多種資源和 Web 界面管理,它同樣建立在 Lucene 之上,并對 Lucene 做了很多擴展,例如支持動態字段及唯一鍵,對查詢結果進行動態分組和過濾等。

    Google SiteSearch

    使用 Google 的站點搜索功能可以方便而快捷地建立一個站內搜索引擎。但是 Google 的站點搜索基于 Google 的網絡爬蟲,所以無法訪問受保護的站點內容或者 Intranet 上的資源。另外,Google 所支持的資源類型也是有限的,我們無法對其進行擴展。

    SearchBlox?

    SearchBlox 是一個商業的搜索引擎構建框架。它本身是一個 J2EE 組件,和我們的框架類似,也支持對網頁和文件系統等資源進行索引,進而進行搜索。


    還需考慮的問題

    本文介紹的思想試圖利用開源的工具解決中小型應用中的常見問題。當然,作為一個框架,它還有很多不足,下面列舉出一些可以進行改進的地方。

    性能考慮

    當需要進行索引的資源數目不多時,隔一定的時間進行一次完全索引不會占用很長時間。使用一臺 2G 內存,Xeon 2.66G 處理器的服務器進行實際測試,發現對數據庫資源的索引占用的時間很少,一千多條記錄花費的時間在 1 秒到 2 秒之內。而對 1400 多個文件進行索引耗時大約十幾秒。但在大型應用中,資源的容量是巨大的,如果每次都進行完整的索引,耗費的時間會很驚人。我們可以通過跳過已經索引的資源內容,刪除已不存在的資源內容的索引,并進行增量索引來解決這個問題。這可能會涉及文件校驗和索引刪除等。

    另一方面,框架可以提供查詢緩存來提高查詢效率??蚣芸梢栽趦却嬷薪⒁患壘彺?,并使用如 OSCache 或 EHCache 實現磁盤上的二級緩存。當索引的內容變化不頻繁時,使用查詢緩存更會明顯地提高查詢速度、降低資源消耗。

    分布式索引

    我們的框架可以將索引分布在多臺機器上。搜索資源時,查詢被 flood 到各個機器上從而獲得搜索結果。這樣可以免去傳輸索引到某一臺中央服務器的過程。當然也可以在非結構化的 P2P 網絡上實現分布式哈希表 (DHT),配合索引復制 (Replication),使得應用程序更為安全,可靠,有伸縮性。在閱讀資料中給出了 一篇關于構建分布式環境下全文搜索的可行性的論文。

    安全性

    目前我們的框架并沒有涉及到安全性。除了依賴資源本身的訪問控制(如受保護的網頁和文件系統等)之外,我們還可以從兩方面增強框架本身的安全性:

    考慮到一個組織的搜索功能對不同用戶的權限設置不一定一樣,可以支持對用戶角色的定義,實行對搜索模塊的訪問控制。
    在資源索引模塊中實現一種機制,讓資源可以限制自己暴露的內容,從而縮小索引模塊的索引范圍。這可以類比 robots 文件可以規定搜索引擎爬蟲的行為。


    通過上文的介紹,我們認識了一個可擴展的框架,由索引模塊和搜索模塊兩部分組成。它可以靈活地適應不同的應用場景。如果需要更獨特的需求,框架本身預留了可以擴展的接口,我們可以通過實現這些接口完成功能的定制。更重要的是這一切都是建立在開源軟件的基礎之上。希望本文能為您揭示開源的力量,體驗用開源工具組裝您自己的解決方案所帶來的莫大快樂。
    posted @ 2009-08-29 00:25 小菜毛毛 閱讀(418) | 評論 (0)編輯 收藏

    方法一:
    本人解決的方法,保證可用。
    添加過濾器(代碼如下)
    package com.cn.util;

    import java.io.* ;
    import javax.servlet.* ;
    import javax.servlet.http.HttpServletResponse;

    public class ForceNoCacheFilter implements Filter {    
     
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException    
    {    
      ((HttpServletResponse) response).setHeader("Cache-Control","no-cache");    
      ((HttpServletResponse) response).setHeader("Pragma","no-cache");    
      ((HttpServletResponse) response).setDateHeader ("Expires", -1);    
      filterChain.doFilter(request, response);    
    }    
    public void destroy()    
    {    
    }    
       public void init(FilterConfig filterConfig) throws ServletException    
    {    
    }    
    }    

    然后在web.xml中添加這個過濾器
    <filter>
        <filter-name>NoCache</filter-name>
        <filter-class>com.cn.util.ForceNoCacheFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>NoCache</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    com.cn.util.ForceNoCacheFilter為剛才過濾器的包名.類名,/*為匹配所有請求。

    這樣你所有的請求都將會傳到服務器處理,不會查看緩存了。

    方法二:
    inComeHttp.url="familyGroup.do?method=query&tmp="+Math.random();
    url上隨意傳一個隨機數
    posted @ 2009-08-26 13:06 小菜毛毛 閱讀(1753) | 評論 (0)編輯 收藏

    W0105010055
    posted @ 2009-08-25 12:18 小菜毛毛 閱讀(93) | 評論 (0)編輯 收藏

    flex多module切換問題
    錯誤描述:

    typeError: Error #
    1034: 強制轉換類型失敗:無法將 mx.graphics::Stroke@b945581 轉換為 mx.graphics.IStroke。
     at mx.charts::AxisRenderer
    /measure()[C:\Work\flex\dmv_automation\projects\datavisualisation\src\mx\charts\AxisRenderer.as:1091]
     at mx.core::UIComponent
    /measureSizes()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:5819]
     at mx.core::UIComponent
    /validateSize()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:5765]
     at mx.managers::LayoutManager
    /validateSize()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:559]
     at mx.managers::LayoutManager
    /doPhasedInstantiation()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:648]
     at Function
    /http://adobe.com/AS3/2006/builtin::apply()
     at mx.core::UIComponent/callLaterDispatcher2()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:8460]
     at mx.core::UIComponent
    /callLaterDispatcher()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:8403]

    錯誤說明:當我在多module切換的時候就抱這個錯,特別要說明的是在切換時的連個module顯示的圖形,一個是自己畫的,一個用的flex自帶的,自己畫的中里面用的是IStroke,但是自帶的圖形是Stroke,所以切換的時候就抱錯,

    解決方法:

    如果你是用的是IModuleInfo的話的load的時候添加ApplicationDomain.currentDomain參數就可以了,

    如:info.load(ApplicationDomain.currentDomain);

    如果你用的是loadModule的話,則這樣

    aa.applicationDomain
    =ApplicationDomain.currentDomain;
        aa.loadModule();


    方法二:
     /*  Create dummy variables.  */
                 // 避免出現:無法將 mx.managers::PopUpManagerImpl@52a09a1 轉換為 mx.managers.IPopUpManager 錯誤
                 private  var dragManager : DragManager;
                 private  var popUpManager : IPopUpManager;
    在應用中添加上如上代碼
    posted @ 2009-08-19 13:35 小菜毛毛 閱讀(1096) | 評論 (0)編輯 收藏

    flex開發中將各個功能分解到模塊中,但在加載各個模塊的時候需要注意一下問題:
    加載方法:
    private function init():void
    {
    module = mx.modules.ModuleManager.getModule("UIModule/HR/Holiday/Config/frmHolidayMain.swf");
    module.addEventListener(mx.events.ModuleEvent.READY,ready);
    module.load();


    // general=ModuleLoader(mx.managers.PopUpManager.createPopUp(this,ModuleLoader));
    //
    //           general.url="test3.swf";
    //          
    //           general.loadModule();
    }
    private function ready(e:ModuleEvent):void
    {
    var moduleInfo:IModuleInfo = e.target as IModuleInfo
    var wind:MDIWindow = new MDIWindow();


    wind.addChild(moduleInfo.factory.create() as DisplayObject);


    testcanvas.windowManager.add(wind);

    }
    需要注意的一點是 module 對象的定義一定要定義為全局的否則ready事件是不能執行的。具體原因不知道,個人理解為到ready方法中無法找到module對象了


    flex 裝載多個module出現的問題Error #1034: 強制轉換類型失敗 收藏
    摘自http://bzhang.javaeye.com/blog/322148
    TypeError: Error #1034: 強制轉換類型失敗:無法將 Object@1aee90b1 轉換為 mx.messaging.messages.IMessage。


    需求背景 :
    通過樹形菜單加載多個不同的module。
    問題現象 :module頁面存在拖動,Popup,Alert或者colorpicker出現錯誤信息:
    TypeError: Error #1034: 強制轉換類型失敗:無法將 mx.managers::PopUpManagerImpl@7155ac1 轉換為 mx.managers.IPopUpManager。
    解決方案 :
    在Application加入如下代碼引用:
         < mx:Script >
             <! [CDATA[
                 import  mx.managers.DragManager;
                 import  mx.managers.IPopUpManager;           
               
                 /*  Create dummy variables.  */
                 // 避免出現:無法將 mx.managers::PopUpManagerImpl@52a09a1 轉換為 mx.managers.IPopUpManager 錯誤
                 private  var dragManager : DragManager;
                 private  var popUpManager : IPopUpManager;
              
                //process....

            ]]>
        </mx:Script>
    問題原因分析 :
    屬于ModuleLoader shared code problem .
    當Module中使用managers時(如PopUpManager,DragManager, HistoryManager等)則可能出現這個問題(當application里在loader之前沒有引入這些manager的引用時)。
    manager 的方法是靜態方法,整個應用程序中創建了一個該manager接口的singleton實例,但module僅在自己的 Application domain中使用該單例, 當多個module使用同一個單例manager且main application沒有使用時,就會出現這個空對象引用問題:第一個引入某manager的module不能將該manager接口的 singleton跟其他module共享,其他module調用該Manager的方法時,應用程序不會再創建該manager接口的實例,這個 module就無法引用到該manager接口的實例,就出現了空對象引用問題.
    參考資料:Flex sdk源碼。

    目前在Application創建了些Application范圍內沒有使用到的"木偶變量",從代碼可讀性上來說不是很好。有其他比較好的解決方案的同學麻煩請告之下,:)

    posted on 2008-11-22 17:33 鉤子 閱讀(1118) 評論(1)  編輯  收藏 所屬分類: jee 、ria 、工作筆記

    <noscript type="text/javascript"> //<![CDATA[ Sys.WebForms.PageRequestManager._initialize('AjaxHolder$scriptmanager1', document.getElementById('Form1')); Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tAjaxHolder$UpdatePanel1'], [], [], 90); //]]> </noscript>
    Feedback
    #   re: FLEX:multiple moduleloader occur #1034 error 2008-11-24 10:14 鉤子
    同事推薦了個更好的辦法:
    在ModuleLoader 的creationComplete方法中加入如下代碼:
    moduleLoader.applicationDomain = ApplicationDomain.currentDomain;
    就可以在Application里切換多個module而不需要在Application里明文引用單例manager聲明。比我上面所說的方法更好的能解決問題而且,代碼可讀性更好。
    另外,推薦在moduleloader做切換的時候,加上:
    moduleLoader.unloadModule再做moduleLoader.loadModule().

    在這里做個小記。

    http://blog.csdn.net/yzsind/archive/2009/03/27/4031066.aspx
    posted @ 2009-08-18 17:31 小菜毛毛 閱讀(2693) | 評論 (0)編輯 收藏

    目標:本文主要介紹聯系的定義及使用。

     一、 聯系
    聯系(Relationship)是指實體集這間或實體集內部實例之間的連接。

     實體之間可以通過聯系來相互關聯。與實體和實體集對應,聯系也可以分為聯系和聯系集,聯系集是實體集之間的聯系,聯系是實體之間的聯系,聯系是具有方向性的。聯系和聯系集在含義明確的情況之下均可稱為聯系。

     按照實體類型中實例之間的數量對應關系,通常可將聯系分為4類,即一對一(ONE TO ONE)聯系、一對多(ONE TO MANY)聯系、多對一(MANY TO ONE)聯系和多對多聯系(MANY TO MANY)。

     二、 建立聯系
    在CDM工具選項板中除了公共的工具外,還包括如下圖所示的其它對象產生工具。

     在圖形窗口中創建兩個實體后,單擊“實體間建立聯系”工具,單擊一個實體,在按下鼠標左鍵的同時把光標拖至別一個實體上并釋放鼠標左鍵,這樣就在兩個實體間創建了聯系,右鍵單擊圖形窗口,釋放Relationship工具。如下圖所示


    三、 四種基本的聯系
    即一對一(ONE TO ONE)聯系、一對多(ONE TO MANY)聯系、多對一(MANY TO ONE)聯系和多對多聯系(MANY TO MANY)。如圖所示

    四、 其他幾類特殊聯系

    除了4種基本的聯系之外,實體集與實體集之間還存在標定聯系(Identify Relationship)、非標定聯系(Non-Identify RelationShip)和遞歸聯系(Recursive Relationship)。

    標定聯系:
    每個實體類型都有自己的標識符,如果兩個實體集之間發生聯系,其中一個實體類型的標識符進入另一個實體類型并與該實體類型中的標識符共同組成其標識符時,這種聯系則稱為標定聯系,也叫依賴聯系。反之稱為非標定聯系,也叫非依賴聯系。
     注意:
    在非標定聯系中,一個實體集中的部分實例依賴于另一個實例集中的實例,在這種依賴聯系中,每個實體必須至少有一個標識符。而在標定聯系中,一個實體集中的全部實例完全依賴于另個實體集中的實例,在這種依賴聯系中一個實體必須至少有一個標識符,而另一個實體卻可以沒有自己的標識符。沒有標識符的實體用它所依賴的實體的標識符作為自己的標識符。


    換句話來理解,在標定聯系中,一個實體(選課)依賴 一個實體(學生),那么(學生)實體必須至少有一個標識符,而(選課)實體可以沒有自己的標識符,沒有標標識符的實體可以用實體(學生)的標識符作為自己的標識符。


     遞歸聯系:
    遞歸聯系是實體集內部實例之間的一種聯系,通常形象地稱為自反聯系。同一實體類型中不同實體集之間的聯系也稱為遞歸聯系。

    例如:在“職工”實體集中存在很多的職工,這些職工之間必須存在一種領導與被領導的關系。又如“學生”實體信中的實體包含“班長”子實體集與“普通學生”子實體集,這兩個子實體集之間的聯系就是一種遞歸聯系。創建遞歸聯系時,只需要單擊“實體間建立聯系”工具從實體的一部分拖至該實體的別一個部分即可。如圖


    五、 定義聯系的特性

    在兩個實體間建立了聯系后,雙擊聯系線,打開聯系特性窗口,如圖所示。


     六、 定義聯系的角色名
    在聯系的兩個方向上各自包含有一個分組框,其中的參數只對這個方向起作用,Role Name為角色名,描述該方向聯系的作用,一般用一個動詞或動賓組表。
    如:“學生 to 課目 ” 組框中應該填寫“擁有”,而在“課目To 學生”組框中填寫“屬于”。(在此只是舉例說明,可能有些用詞不太合理)。

    七、 定義聯系的強制性
    Mandatory 表洋這個方向聯系的強制關系。選中這個復選框,則在聯系線上產生一個聯系線垂直的豎線。不選擇這個復選框則表示聯系這個方向上是可選的,在聯系線上產生一個小圓圈。

    八、 有關聯系的基數
    聯系具有方向性,每個方向上都有一個基數。

    舉例,
    “系”與“學生”兩個實體之間的聯系是一對多聯系,換句話說“學生”和“系”之間的聯系是多對一聯系。而且一個學生必須屬于一個系,并且只能屬于一個系,不能屬于零個系,所以從“學生”實體至“系”實體的基數為“1,1”,從聯系的另一方向考慮,一個系可以擁有多個學生,也可以沒有任何學生,即零個學生,所以該方向聯系的基數就為“0,n”,如圖所示

    待續。

    posted @ 2009-08-13 15:23 小菜毛毛 閱讀(327) | 評論 (0)編輯 收藏

    目標:
    本文主要介紹數據項、新增數據項、數據項的唯一性代碼選項和重用選項等。

    一、數據項
    數據項(Data Item)是信息存儲的最小單位,它可以附加在實體上作為實體的屬性。
    注意:模型中允許存在沒有附加至任何實體上的數據項。

    二、新建數據項
    1)使用“Model”---> Data Items 菜單,在打開的窗口中顯示已有的數據項的列表,點擊 “Add a Row”按鈕,創建一個新數據項,如圖所示


    2)當然您可以繼續設置具體數據項的Code、DataType、Length等等信息。這里就不再詳細說明了。

    三、數據項的唯一性代碼選項和重用選項
    使用Tools--->Model Options->Model Settings。在Data Item組框中定義數據項的唯一性代碼選項(Unique Code)與重用選項(Allow Reuse)。
    注意:
    如果選擇Unique Code復選框 ,每個數據項在同一個命名空間有唯一的代碼,而選擇Allow reuse ,一個數據項可以充當多個實體的屬性。


    四、在實體中添加數據項
    1)雙擊一個實體符號,打開該實體的屬性窗口。
    2)單擊Attributes選項卡,打開如下圖所示窗口


    注意:
    Add a DataItem 與 Reuse a DataItem的區別在于
    Add a DataItem 情況下,選擇一個已經存在的數據項,系統會自動復制所選擇的數據項。如果您設置了UniqueCode選項,那系統在復制過程中,新數據項的Code會自動生成一個唯一的號碼,否則與所選擇的數據項完全一致。


    Reuse a DataItem情況下,只引用不新增,就是引用那些已經存在的數據項,作為新實體的數據項。

    待續。
    0
    0
    (請您對文章做出評價)
    posted @ 2009-08-13 15:23 小菜毛毛 閱讀(338) | 評論 (0)編輯 收藏

    僅列出標題
    共17頁: First 上一頁 9 10 11 12 13 14 15 16 17 下一頁 
    主站蜘蛛池模板: 亚洲AV无码乱码国产麻豆穿越| 日本一区二区三区免费高清| 亚洲精品99久久久久中文字幕 | 免费中文字幕在线观看| 日韩亚洲不卡在线视频中文字幕在线观看 | 精品熟女少妇a∨免费久久| 亚洲国产精品国自产拍电影| 国产成人精品无码免费看| 国产精品亚洲аv无码播放| 久久久久国产免费| 亚洲综合色丁香麻豆| 波多野结衣在线免费视频| 亚洲精品无码专区久久| 四虎免费久久影院| 久久99久久成人免费播放| 久久久久亚洲AV成人无码网站| 曰批全过程免费视频播放网站| 亚洲中字慕日产2021| 国产精品免费视频网站| 成在线人视频免费视频 | 久久亚洲国产欧洲精品一| 99爱在线精品视频免费观看9 | 亚洲成a人片在线观| 天天拍拍天天爽免费视频| 免费激情网站国产高清第一页| 亚洲愉拍99热成人精品热久久| 91福利免费体验区观看区| 亚洲欧美日韩自偷自拍| 国产亚洲午夜高清国产拍精品| 最近最新高清免费中文字幕| 亚洲av日韩专区在线观看| 伊人久久大香线蕉亚洲五月天 | 免费国产黄网站在线观看动图 | 亚洲阿v天堂在线| 黄页网站在线观看免费高清| 粉色视频在线观看www免费| 亚洲视频2020| 亚洲电影日韩精品| 亚欧免费视频一区二区三区| 特色特黄a毛片高清免费观看| 麻豆亚洲AV永久无码精品久久 |