2007年7月16日

          Mondrian是一個(gè)開放源代碼的Rolap服務(wù)器,使用java開發(fā)的。它實(shí)現(xiàn)了xmla和jolap規(guī)范,而且自定義了一種使用mdx語言的客戶端接口。Mondrian是olap服務(wù)器,而不是數(shù)據(jù)倉庫服務(wù)器,因此Mondrian的元數(shù)據(jù)主要包括olap建模的元數(shù)據(jù),不包括從外部數(shù)據(jù)源到數(shù)據(jù)庫轉(zhuǎn)換的元數(shù)據(jù)。也就是說Mondria的元數(shù)據(jù)僅僅包括了多維邏輯模型,從關(guān)系型數(shù)據(jù)庫到多維邏輯模型的映射,存取權(quán)限等信息。在功能上,Mondrian支持共享維和成員計(jì)算,支持星型模型和雪花模型的功能。
          Mondrian中使用物理的xml文件存儲(chǔ)元數(shù)據(jù),它的設(shè)計(jì)者規(guī)定了xml文件的格式。下面簡單介紹一下它是如何存儲(chǔ)元數(shù)據(jù)的。

          Element Description
          根元素
          <Schema> Collection of Cubes, Virtual cubes, Shared dimensions, and Roles.
          邏輯元素
          <Cube> A collection of dimensions and measures, all centered on a fact table.
          <VirtualCube> A cube defined by combining the dimensions and measures of one or more cubes.
          <Dimension>
          <DimensionUsage> Usage of a shared dimension by a cube.
          <Hierarchy>
          <Level>
          <Property>
          <Measure>
          物理元素
          <Table> Fact- or dimension table.
          <View> Defines a 'table' using a SQL query, which can have different variants for different underlying databases.
          <Join> Defines a 'table' by joining a set of queries.
          存取控制
          <Role> An access-control profile.
          <SchemaGrant> A set of rights to a schema.
          <CubeGrant> A set of rights to a cube.
          <HierarchyGrant> A set of rights to a hierarchy and levels within that hierarchy.
          <MemberGrant> A set of rights to a member and its children.
          其他
          <Parameter>
          <Table>
          <Table>



          一個(gè)模式定義一個(gè)多維數(shù)據(jù)庫,它包括一個(gè)邏輯模型,由立方體,層次,成員和邏輯模型到物理模型的映射構(gòu)成。一個(gè)邏輯模型由可以用MDX語言來查詢。Mondrain的模型由xml文件來描述。現(xiàn)在創(chuàng)建模式的唯一途徑是用文本編輯a器編輯xml文件。Xml的語法不是太復(fù)雜,因此沒有想象中的那么難。目前正在開發(fā)一個(gè)圖形界面的程序來創(chuàng)建和修改模式。
          一個(gè)模式最重要的組成部分是立方體,度量和維:在一個(gè)主題域中立方體是維和度量的集合。一個(gè)度量是一個(gè)可測量的數(shù)值,比如產(chǎn)品銷售的數(shù)量或者詳細(xì)清單的價(jià)格
          一個(gè)維是一個(gè)屬性或者是屬性的集合, 通過維你可以將度量劃分到字類中。比如:你希望將銷售產(chǎn)品按顏色,顧客性別,售出的商店分為八個(gè)部分,那么顏色,性別,商店都是維。

          下面是一個(gè)簡單的模型定義的例子:
          <Schema>
          <Cube name="Sales">
          <Table name="sales_fact_1997"/>
          <Dimension name="Gender" foreignKey="customer_id">
          <Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">
          <Table name="customer"/>
          <Level name="Gender" column="gender" uniqueMembers="true"/>
          </Hierarchy>
          </Dimension>
          <Dimension name="Time" foreignKey="time_id">
          <Hierarchy hasAll="false" primaryKey="time_id">
          <Table name="time_by_day"/>
          <Level name="Year" column="the_year" type="Numeric"
          uniqueMembers="true"/>
          <Level name="Quarter" column="quarter"
          uniqueMembers="false"/>
          <Level name="Month" column="month_of_year" type="Numeric"
          uniqueMembers="false"/>
          </Hierarchy>
          </Dimension>
          <Measure name="Unit Sales" column="unit_sales"
          aggregator="sum" formatString="#,###"/>
          <Measure name="Store Sales" column="store_sales"
          aggregator="sum" formatString="#,###.##"/>
          </Cube>
          </Schema>

          這個(gè)模型包含了一個(gè)銷售cube,這個(gè)cube有兩個(gè)維,時(shí)間和性別維;兩個(gè)度量,銷售數(shù)量和銷售總額。
          我們可以在這個(gè)模型上寫一個(gè) MDX 查詢:
          select {[Measures].[Unit Sales], [Measures].[Store Sales]} on columns,
          {[Time].[1997].[Q1].descendants} on rows
          from [Sales]
          where [Gender].[F]
          這 個(gè)查詢涉及到了銷售立方體, 每一個(gè)維 [Measures], [Time], [Gender], 這些維的多個(gè)成員. 結(jié)果如下:
          [Time] [Measures].[Unit Sales] [Measures].[Store Sales]
          [1997].[Q1] 0 0
          [1997].[Q1].[Jan] 0 0
          [1997].[Q1].[Feb] 0 0
          [1997].[Q1].[Mar] 0 0

          下面詳細(xì)地介紹一下模式定義:
          一個(gè)立方體是一個(gè)或者多個(gè)維和度量的集合,通常是一個(gè)事實(shí)表,這里是 ‘sales_fact_1997". 事實(shí)表保存了需要計(jì)算的列和包含維的參考表.
          <Cube name="Sales">
          <Table name="sales_fact_1997"/>
          ...
          </Cube>
          這里用 <Table> 元素定義事實(shí)表. 如果事實(shí)表 不在默認(rèn)的模式中, 你可以用"schema"屬性指定一個(gè)明確地模式,例如:
          <Table schema="foodmart" name="sales_fact_1997"/>
          你也可以利用 <View> 和 <Join> 結(jié)構(gòu)來創(chuàng)建更復(fù)雜的sql .
          度量
          銷售立方體定義了兩個(gè)維 "Unit Sales" 和 "Store Sales".
          <Measure name="Unit Sales" column="unit_sales"
          aggregator="sum" formatString="#,###"/>
          <Measure name="Store Sales" column="store_sales"
          aggregator="sum" formatString="#,###.00"/>
          每個(gè)度量有一個(gè)名字,對應(yīng)事實(shí)表中的一列, 采用一個(gè)聚集函數(shù) (usually "sum").
          一個(gè)可選的格式字符串指定了值如何被打印. 這里我們選擇銷售數(shù)量不帶小數(shù)的輸出(因?yàn)殇N售數(shù)量是整數(shù)) ,銷售總額帶2位小數(shù) . 符號(hào)',' 和 '.' 是對地區(qū)敏感的, 因此如果是在意大利運(yùn)行, 銷售總額可能會(huì)出現(xiàn) "48.123,45". 你可以用 advanced format strings來實(shí)現(xiàn)更嚴(yán)格的效果.度量值不是從列中來的,而是從立方體的單元中來的

          性別維由單一的層次組成,僅有一層。
          <Dimension name="Gender" foreignKey="customer_id">
          <Hierarchy hasAll="true" primaryKey="customer_id">
          <Table name="customer"/>
          <Level name="Gender" column="gender" uniqueMembers="true"/>
          </Hierarchy>
          </Dimension>
          對于任意給定的銷售, 性別維是指購買改產(chǎn)品的客戶的性別. 它通過連接事實(shí)表"sales_fact_1997.customer_id"和維表"customer.customer_id"
          來表示 。"gender" 包括兩個(gè)值, 'F' 和 'M', 因此性別維包含的成員: [Gender].[F] and [Gender].[M]. 因?yàn)?hasAll="true", 系統(tǒng)產(chǎn)生一個(gè)特別的 'all' 層, 僅包括一個(gè)成員 [All Genders].
          一個(gè)維可以包含多個(gè)層次:
          <Dimension name="Time" foreignKey="time_id">
          <Hierarchy hasAll="false" primaryKey="time_id">
          <Table name="time_by_day"/>
          <Level name="Year" column="the_year" type="Numeric"
          uniqueMembers="true"/>
          <Level name="Quarter" column="quarter"
          uniqueMembers="false"/>
          <Level name="Month" column="month_of_year" type="Numeric"
          uniqueMembers="false"/>
          </Hierarchy>
          <Hierarchy name="Time Weekly" hasAll="false" primaryKey="time_id">
          <Table name="time_by_week"/>
          <Level name="Year" column="the_year" type="Numeric"
          uniqueMembers="true"/>
          <Level name="Week" column="week"
          uniqueMembers="false"/>
          <Level name="Day" column="day_of_week" type="String"
          uniqueMembers="false"/>
          </Hierarchy>
          </Dimension>
          第一個(gè)層次沒有指定名稱.缺省的情況下,一個(gè)層次擁有和它的維相同的名稱。,因此第一個(gè)層次成為"Time".這些層次沒有太多的共同之處,他們甚至沒有相同的表,除非它們連接了實(shí)施表中的同一列"time_id"。在一個(gè)維上存在兩個(gè)層次的原因是這樣對最終用戶是有用的. 如果一個(gè)維上存在兩個(gè)層次, MDX會(huì)強(qiáng)制不允許在一個(gè)查詢中同時(shí)用到他們.
          A dimension can live in the fact table:
          <Cube name="Sales">
          <Table name="sales_fact_1997"/>
          ...
          <Dimension name="Payment method">
          <Hierarchy hasAll="true">
          <Level name="Payment method" column="payment_method" uniqueMembers="true"/>
          </Hierarchy>
          </Dimension>
          </Cube>
          每個(gè)維包含有多層組成的一個(gè)層次,

          大多數(shù)維都是僅有一個(gè)層次,但有時(shí)候一個(gè)維有多個(gè)層次。比如:你可能希望在時(shí)間維上從天聚集到月,季度和年;或者從天聚集到周和年。這兩種層次都是從天到年,但是聚集的路徑不同。大多數(shù)層次有全成員,全成員包括層次的所有成員,因此能夠代表他們的總合。它通常命名為'All something',比如:'All stores'.




          星型模式和雪花模式
          mondrian支持星型模式和雪花模式。下面介紹一下雪花模式的建模,它需要用到操作符 <Join>.比如:
          <Cube name="Sales">
          ...
          <Dimension name="Product" foreignKey="product_id">
          <Hierarchy hasAll="true" primaryKey="product_id" primaryKeyTable="product">
          <Join leftKey="product_class_id" rightAlias="product_class" rightKey="product_class_id">
          <Table name="product"/>
          <Join leftKey="product_type_id" rightKey="product_type_id">
          <Table name="product_class"/>
          <Table name="product_type"/>
          </Join>
          </Join>
          ...
          </Hierarchy>
          </Dimension>
          </Cube>
          這里定義一個(gè) "Product" 維 由三個(gè)表構(gòu)成. 事實(shí)表連接 表"product" (通過外鍵 "product_id"),表"product"連接表"product_class" (通過外鍵 "product_class_id"),表"product_class"連接表 "product_type" (通過外鍵 "product_type_id"). 我們利用 <Join> 元素的循環(huán)嵌套, <Join>帶有兩個(gè)操作對象; 操作對象可能是表,連接或者查詢 。
          按照操作對象行的數(shù)目來安排次序,表 "product" 的行數(shù)最大, 因此它首先出現(xiàn)連接事實(shí)表;然后是表 "product_class"和 "product_type",在雪花的末端擁有的行數(shù)最小.
          注意外部元素 <Join>有一個(gè)屬性 rightAlias. 這是必要的,因?yàn)閖oin 的右邊(是內(nèi)部元素 <Join> ) 有可能是許多表組成的.這種情況下不需要屬性leftAlias,因?yàn)榱?leftKey 很明確的來自表 "product".

          共享維
          當(dāng)為一個(gè)連接生成SQL的時(shí)候, mondrian 需要知道連接哪一個(gè)列. 如果一正在連接一個(gè)多表連接, 你需要告訴它連接這些表里的哪一個(gè)表,哪一個(gè)列.
          因?yàn)楣蚕砭S不屬于一個(gè)cube,你必須給它們一個(gè)明確的表 (或者數(shù)據(jù)源). 當(dāng)你在一個(gè)特別的cube里用他們的時(shí)候, 你要指定外鍵 foreign key. 下面的例子顯示了 Store Type 維被 連接到 Sales cube ,用了外鍵 sales_fact_1997.store_id, 并且被連接到Warehouse cube ,用了外鍵 warehouse.warehouse_store_id :
          <Dimension name="Store Type">
          <Hierarchy hasAll="true" primaryKey="store_id">
          <Table name="store"/>
          <Level name="Store Type" column="store_type" uniqueMembers="true"/>
          </Hierarchy>
          </Dimension>

          <Cube name="Sales">
          <Table name="sales_fact_1997"/>
          ...
          <DimensionUsage name="Store Type" source="Store Type" foreignKey="store_id"/>
          </Cube>

          <Cube name="Warehouse">
          <Table name="warehouse"/>
          ...
          <DimensionUsage name="Store Type" source="Store Type" foreignKey="warehouse_store_id"/>
          </Cube>




          虛擬 cubes
          父子層次
          一個(gè)使用方便的層次 有一個(gè)嚴(yán)格的層的集合, 成員與層緊密的聯(lián)系.比如,在 Product 層次中, 任何產(chǎn)品名稱層的成員在商標(biāo)層上都有一個(gè)父親 ,商標(biāo)層上的成員在產(chǎn)品子目錄層也都有一個(gè)父親. 這種結(jié)構(gòu)對于現(xiàn)實(shí)世界中的數(shù)據(jù)有時(shí)候太嚴(yán)格了.
          一個(gè)父子層次只有一層 (不計(jì)算 'all' 層), 但是任何成員可以在同一層上有父親成員. 一個(gè)典型的例子是Employees 層次:
          <Dimension name="Employees" foreignKey="employee_id">
          <Hierarchy hasAll="true" allMemberName="All Employees" primaryKey="employee_id">
          <Table name="employee"/>
          <Level name="Employee Id" uniqueMembers="true" type="Numeric"
          column="employee_id" nameColumn="full_name"
          parentColumn="supervisor_id" nullParentValue="0">
          <Property name="Marital Status" column="marital_status"/>
          <Property name="Position Title" column="position_title"/>
          <Property name="Gender" column="gender"/>
          <Property name="Salary" column="salary"/>
          <Property name="Education Level" column="education_level"/>
          <Property name="Management Role" column="management_role"/>
          </Level>
          </Hierarchy>
          </Dimension>
          這里parentColumn 和nullParentValue是重要的屬性:
          屬性parentColumn 是一個(gè)成員連接到它父親成員的列名。在這種情況下, 它是指向雇員經(jīng)理的外鍵。元素<Level>的子元素 <ParentExpression> 是與屬性 parentColumn 有相同作用的,但是元素允許定義任意的SQL表達(dá)式, 就像元素 <Expression>. 屬性 parentColumn (或者 元素<ParentExpression>) 是維一向Mondrian指出 層次有父子結(jié)構(gòu)的。
          屬性 nullParentValue 是指明成員沒有父成員的值 。 缺省情況下 nullParentValue="null", 但是因?yàn)樵S多數(shù)據(jù)庫不支持null, 建模時(shí) 用其他值來代替空值,0和-1.

          物理結(jié)構(gòu)
          member reade
          member reader 是訪問成員的方法. 層次通常以維表為基礎(chǔ)建立的 , 因此要用sql來構(gòu)造.但是甚至你的數(shù)據(jù)沒有存在于 RDBMS, 你可以通過一個(gè) Java 類來訪問層次。(自定義 member reader)
          Here are a couple of examples:
          DateSource (to be written)生成一個(gè)時(shí)間層次. 按常規(guī),數(shù)據(jù)倉庫工具生成一個(gè)表 ,每天包含一行。但是問題是這個(gè)表需要裝載,并且隨著時(shí)間的變化能夠添加更多的行。 DateSource 在內(nèi)存中按照要求生成日期成員.
          FileSystemSource (to be written) 按照目錄和文件的層次描述文件系統(tǒng)。 Like the time hierarchy created by DateSource, this is a virtual hierarchy: the member for a particular file is only created when, and if, that file's parent directory is expanded.
          ExpressionMemberReader (to be written) 創(chuàng)建了一個(gè)基于表達(dá)式的層次。
          自定義member reader 必須實(shí)現(xiàn)接口 mondrian.rolap.MemberSource. 如果你需要實(shí)現(xiàn)一個(gè)更大的成員操作集合, 需要實(shí)現(xiàn)接口 interface mondrian.rolap.MemberReader; 否則, Mondrian在 mondrian.rolap.CacheMemberReader中封裝 你的 reader類.你的 member reader 必須有一個(gè)公共的構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)擁有參數(shù)(Hierarchy,Properties),拋出未檢查的錯(cuò)誤.
          Member readers 用 元素<Hierarchy> 的屬性memberReaderClass來聲明; 任何 <Parameter> 子元素通過屬性構(gòu)造函數(shù)來傳遞.
          這是一個(gè)例子:
          <Dimension name="Has bought dairy">
          <Hierarchy hasAll="true" memberReaderClass="mondrian.rolap.HasBoughtDairySource">
          <Level name="Has bought dairy" uniqueMembers="true"/>
          <Parameter name="expression" value="not used"/>
          </Hierarchy>
          </Dimension>
          Cell readers
          <Measure name="name" cellReaderClass="com.foo.MyCellReader">
          類 "com.foo.MyCellReader" 實(shí)現(xiàn)了接口interface mondrian.olap.CellReader.


          存取控制
          可以定義存取控制的屬性(角色), 作為模式的一部分, 并且可以在建立連接的時(shí)候設(shè)置角色。
          定義角色
          角色可以通過 元素<Role>來設(shè)置 , 它是元素<Schema> 的直接的子元素.
          下面是一個(gè)關(guān)于角色的例子:
          <Role name="California manager">
          <SchemaGrant access="none">
          <CubeGrant cube="Sales" access="all">
          <HierarchyGrant hierarchy="[Store]" access="custom" topLevel="[Store].[Store Country]">
          <MemberGrant member="[Store].[USA].[CA]" access="all"/>
          <MemberGrant member="[Store].[USA].[CA].[Los Angeles]" access="none"/>
          </HierarchyGrant>
          <HierarchyGrant hierarchy="[Customers]" access="custom" topLevel="[Customers].[State Province]" bottomLevel="[Customers].[City]">
          <MemberGrant member="[Customers].[USA].[CA]" access="all"/>
          <MemberGrant member="[Customers].[USA].[CA].[Los Angeles]" access="none"/>
          </HierarchyGrant>
          <HierarchyGrant hierarchy="[Gender]" access="none"/>
          </CubeGrant>
          </SchemaGrant>
          </Role>
          元素 <SchemaGrant> 定義了模式中缺省的對象方問權(quán)限. 訪問屬性可以是 "all" 或者 "none"; 這個(gè)屬性可以被具體的權(quán)限對象繼承. 在這個(gè)例子中, 因?yàn)?access="none", 用戶只能瀏覽"Sales" 立方體, 這里明確的賦予了這個(gè)權(quán)限.
          元素 <CubeGrant> 定義了立方體的訪問權(quán)限. 就像 <SchemaGrant>, 屬性access 可以是"all" 或者 "none", 并且能夠被cube中具體的子對象繼承.
          元素 <HierarchyGrant>定義了層次的訪問權(quán)限. 屬性access 可以是"all", 意思是所有的members都是可見的; "none",意思是 hierarchy的存在對用戶是隱藏的; "custom", 你可以利用屬性 topLevel 定義可見的最高層 (阻止用戶 進(jìn)行上卷操作, 比如瀏覽稅收 上卷到 Store Country 層); 或者用屬性 bottomLevel 定義可見的最底層 (這里阻止用戶查看顧客個(gè)人的細(xì)節(jié)數(shù)據(jù));或者控制用戶查看哪一個(gè)成員集合,通過嵌套定義元素 <MemberGrant>.
          你也可以只定義元素 <MemberGrant> ,如果模式的<HierarchyGrant> 有屬性access="custom". Member grants 賦予 (或者取消) 訪問給定的成員, 以及它的所有子成員.
          posted @ 2008-03-26 22:30 edsonjava 閱讀(926) | 評論 (0)編輯 收藏
           
          改了不少JPivot/mondrian代碼,還修正了jpivot一個(gè)bug。

          對JPivot的jfreechart和drillthrough顯示做了增強(qiáng),終于可以拿出去給人用了。

          先說說性能問題: 先是找了一臺(tái)閑置的IBM X445 PC Server,4×2GHZ CPU,8G內(nèi)存,2×146G硬盤,操作系統(tǒng) windows 2000 , 開啟AWE 3G參數(shù)。然后裝Oracle 10g,數(shù)據(jù)倉庫模式,使用了4G AWE內(nèi)存共約4.5GB內(nèi)存。再建成一張1600萬用戶數(shù)據(jù)寬表,寬表一律使用bitmap索引,還有其他20個(gè)左右維表。 然后就簡單了,寫mondrian Cube,配JPivot。 最后搞下來的結(jié)果是:基本上mondrian 每次做group by 操作最長不超過30秒,一般在20秒左右。用戶基本可以接受。問了使用NCR的朋友,說NCR使用自己的數(shù)據(jù)庫,也基本是這樣的一個(gè)性能。 PS:偷偷問一聲,在這基礎(chǔ)上,性能還能改進(jìn)否?

           

          再說說方向問題: 我們現(xiàn)在使用2個(gè)OLAP,一個(gè)是jpivot + mondrian ,屬于ROLAP;另一個(gè)是BO intelligence + essbase,屬于MOLAP。目前的感覺是,由于DB性能強(qiáng)悍,導(dǎo)致ROLAP和MOLAP在性能上相差不大。同時(shí)ROLAP可以直接和報(bào)表系統(tǒng)共用同一張表。而MOLAP則需要使用工具來打CUBE做數(shù)據(jù)轉(zhuǎn)換,這樣在開發(fā)和維護(hù)工作量上,MOLAP比ROLAP大。 另外往往業(yè)務(wù)部門分析到最后,就是要看明細(xì)數(shù)據(jù)了,這個(gè)時(shí)候MOLAP的前端工具往往不能做好支持。而jpivot則無此問題。 綜上所述,我目前好像還沒看到必須用MOLAP的理由,聽說華為原來用M$ 的OLAP,后來好像支持不住了,就直接用回了BO 報(bào)表,呵呵。

           

          JPivot的問題: 操作太復(fù)雜,必須對OLAP的概念有清晰的了解,普通用戶無法使用。與mondrian 集成不夠緊密。mondrian不提供數(shù)據(jù)鉆取功能,該功能是jpivot自己做的,所以會(huì)導(dǎo)致數(shù)據(jù)類型格式丟失。鉆取詳細(xì)數(shù)據(jù)量無限制,導(dǎo)致內(nèi)存溢出。界面比較難看,操作方式非主流使用jpivot自己的mvc框架,不易其他框架集成 總體來說,jpivot目前已經(jīng)不是一個(gè)玩具了,完全可以用于企業(yè)級的操作,而且定位在高端業(yè)務(wù)分析人員。


          拿出來開源比較困難,一方面jpivot在不停升級,另一方面我在修改的時(shí)候不顧一切,在jpivot中亂引用了mondrian代碼,還把mondrian部分無用代碼全刪了。這樣,我就在這個(gè)帖里把能共享部分都在這里帖出來。 首先是我優(yōu)化后的界面。 1.圖標(biāo)用了pentaho里面的圖標(biāo)。 2.jpivot里面其實(shí)支持3D餅圖,只是選項(xiàng)未開,我先將jfreechart升級成1.0.2,又對餅圖、線圖等做了美觀。 3.drillthrough是jpivot相對其他olap產(chǎn)品的殺手級功能,但是有不少細(xì)節(jié)未完善。我基本都一一補(bǔ)上。 在界面上可以看出,我添加了一個(gè)CSV導(dǎo)出功能(改了WCF庫),同時(shí)限制最大導(dǎo)出20萬行記錄(改了jpivot)。界面上顯示的“訪問次數(shù)”是measure的名字,實(shí)際上應(yīng)該顯示“訪問時(shí)間”,該問題暫時(shí)無解。另外修正了一下numberformat、dateformat不正確的一些問題。 4.excel導(dǎo)出時(shí),格式很難看,但是由于excel本身只支持256色,無法顯示web上的底色,所以我修改了只顯示藍(lán)色的border,底色一律為白。 附件中rar里面是web的CSS文件、Excel的生成文件和jpivot的圖表生成部分代碼,感興趣的朋友各取所需吧


          另外還把jpviot完全整合到我自己的系統(tǒng)中去了,呵呵。 可以在系統(tǒng)web界面上編寫Cube和MDX定義,Cube和MDX為一對多關(guān)系。Cube通過xsd來做校驗(yàn)。開發(fā)Cube和MDX的時(shí)候可以隨時(shí)做預(yù)覽。 然后再把一個(gè)MDX在界面發(fā)布成一個(gè)單獨(dú)的OLAP分析。 下一步的目標(biāo)是將數(shù)據(jù)權(quán)限與jpivot做整合,由于Cube的xml是由系統(tǒng)自動(dòng)生成的,所以mondrian的role配置也可以由系統(tǒng)根據(jù)配置自動(dòng)生成。 這部分代碼涉及我的系統(tǒng)和框架比較深,所以不帖代碼了哈,大家自己搞搞2天也就出來了


          還做了個(gè)及其變態(tài)的功能,就是把界面上所有顯示的jpivot cell,一個(gè)個(gè)的去取出鉆取數(shù)據(jù)的measure,然后生成csv文件,打成zip包給用戶下載或發(fā)到其他接口。 當(dāng)時(shí)我化了整整一個(gè)禮拜鉆研mondrian代碼,希望可以不用那么傻傻個(gè)一個(gè)個(gè)去鉆,結(jié)果失敗...

          我在用Jpivot的時(shí)候,發(fā)現(xiàn)用mondrian是影響取數(shù)性能其中的一個(gè)瓶頸........ 經(jīng)研究.....我們自己修改了jpivot和wcf的一些代碼來適應(yīng)我們自己的項(xiàng)目.........以下是我做的一些修改.....想聽聽大家的意見 1.脫離mondrian.直接寫dll的方式取數(shù),然后生成XML數(shù)據(jù) .我發(fā)現(xiàn)脫離mondrian自己寫了一個(gè)DLL去調(diào)用MSSQL 2000 的OLAP,數(shù)度很快........... 2 .修改界面的顯示方式 上面也說道.Jpivot的界面一個(gè)不好看,二是用起來很不方便.比如取維度等的時(shí)候....一層一層的進(jìn)去實(shí)在很麻煩.... a.修改取維度的方式 我們參照ms的做法 做成一個(gè)了一個(gè)樹的取數(shù),研究jpivot里面的代碼.如果直接用jpivot的代碼取數(shù)據(jù)十分慢.這樣我自己通過AJAX和Jpivot結(jié)合,動(dòng)態(tài)生成樹的結(jié)構(gòu),然后在樹上取維度的時(shí)候,直接通過鼠標(biāo)托到選擇維度textbox上.........依照條件生成相應(yīng)MDX....顯示數(shù)據(jù)..... b.修改數(shù)據(jù)顯示的樣式.和取維度,生成MDX分開了. 顯示數(shù)據(jù)我用了另外一種方式顯示.就是用Frame分為上下兩層.....上下兩層可以通過按鈕擴(kuò)大整個(gè)頁面........ 3. 集成在自己的框架中 集成在自己的框架中,我個(gè)人覺得是比較麻煩的一件事情.一點(diǎn)小事沒有搞好就很麻煩...因?yàn)槲覀兪怯肑SF開發(fā)的.所以依照J(rèn)pivot....自己寫了一些組件來輔助開發(fā),我自己開發(fā)主要改成比較像ms 2000 的olap分析方法... 還未完成的需求 JFreeChar的功能還需要加強(qiáng). 個(gè)人感覺:jpivot是很不錯(cuò).可是不能一拿來就用..我發(fā)現(xiàn)好多人用jpivot都要修改好多東西....但是修改起來又比較麻煩....java,j2ee,xml ,xslt,javascript,taglib.....好多東西都要懂.....
          posted @ 2008-03-26 22:28 edsonjava 閱讀(2244) | 評論 (1)編輯 收藏
           

          This documentation is related to the displaytag 1.1.x releases.

          The latest available release is 1.1.1

          Displaytag 1.1 offers several enhancements over 1.0: the most notable news are support for partial lists and enhanced decorator APIs, but there is also a lot more. Be sure to read the migration guide for upgrading an existing application from displaytag 1.0. A full changelog is also available.

          Overview

          The display tag library is an open source suite of custom tags that provide high-level web presentation patterns which will work in an MVC model. The library provides a significant amount of functionality while still being easy to use.

          What can I do with it?

          Actually the display tag library can just... display tables! Give it a list of objects and it will handle column display, sorting, paging, cropping, grouping, exporting, smart linking and decoration of a table in a customizable XHTML style.

          The tables in the sample images below were generated from lists using the <display:table> tag:

          sample tables produced with the display:table tag
          posted @ 2008-02-23 23:47 edsonjava 閱讀(525) | 評論 (0)編輯 收藏
           
          近在論證java領(lǐng)域的開源BI前端框架,把隨手記得東西和大家分享下.
          因?yàn)橹豢戳藥滋欤袥]時(shí)間整理所以看起來比較亂,也不是很深入。

          目前在java領(lǐng)域較常見的BI前端框架(商業(yè)智能項(xiàng)目)主要有以下幾個(gè)Pentaho,spagoBi, OpenI, JASPER intelligence等開源框架。

           他們都有自己的強(qiáng)項(xiàng)和不足,下面簡要介紹下:

          輕量級的:

          OpenI使用Mondrian和Jpivot框架,報(bào)表引擎是jasper report,數(shù)據(jù)挖掘接口是R-Project,

          相對來說開發(fā)和學(xué)習(xí)比較簡單,而且OpenI支持使用MS的數(shù)據(jù)倉庫(xmla),但是其國際化比較失敗(中文亂碼),要深入改造。

           JASPER intelligence也是個(gè)輕型項(xiàng)目,對jasper report的支持最好,所以報(bào)表部分比較好。

           重量級的:

          PentahospagoBi是兩個(gè)比較大的框架了,集成了相當(dāng)多的開源項(xiàng)目,JfreeReport、Mondrian、Kettle、Weka基本都使用了。特別適合大型復(fù)雜項(xiàng)目的開發(fā)。

                Pentaho在中國使用的比較多,文檔什么的也多一點(diǎn)。尤其值得一提的是網(wǎng)絡(luò)上對他的中文支持做的相當(dāng)好,很多志愿者翻譯了它的文檔。這給我們開發(fā)帶來很大便利。

           

                Pentaho的模塊工作流引擎、中心資源庫、審計(jì)組件、報(bào)表設(shè)計(jì)工具、ETL工具、OLAP Server、多維展示、數(shù)據(jù)挖掘組件各種組建都有。

          而且Pentaho得到了很大的投資,開發(fā)后勁很大,而且會(huì)有付費(fèi)的官方發(fā)售版本。 

          http://blog.csdn.net/dust_bug/archive/2006/09/18/1240753.aspx

          這個(gè)是Pentaho源代碼閱讀報(bào)告》,介紹Pentaho構(gòu)架相當(dāng)?shù)娜妗?O:P> 

          Pentaho的中文論壇在http://www.bipub.org/ 

          Pentaho相對spagoBi來說功能較強(qiáng),尤其是工作流一塊做的相當(dāng)不錯(cuò)。

          官方站的demos在http://www.pentaho.com/products/demos/

           spagoBi功能也很強(qiáng),尤其是最近發(fā)布的1。9版本,在http://spagobi.eng.it:8080/sbiportal/faces/public/exo(或http://spagobi.eng.it:8080/sbiportal

          的demos里展現(xiàn)了spagoBi很多功能。

           后記
          這幾款BI框架因?yàn)槎际情_源的前端框架,所以核心部分使用的還是一些開源項(xiàng)目,

          Mondrian,Jpivot,JfreeReport,所以在使用的時(shí)候搭建合適的框架會(huì)占用項(xiàng)目很大一部分時(shí)間,但是一旦框架搭建好了,基本就可以象流水線一樣出報(bào)表了。

          但是期望在原始功能上添加性能功能是比較麻煩的,為了一個(gè)新加的功能可能需要相當(dāng)長的時(shí)間來實(shí)現(xiàn)。

          另外這些開源框架的權(quán)限管理都不怎么強(qiáng),可能需要改造。

          另外,全球話的問題也是問題。象OpenI完全不支持中文,必須改造。

          posted @ 2008-02-23 23:38 edsonjava 閱讀(961) | 評論 (0)編輯 收藏
           

          我們都知道“瞎子摸象”的故事。不同的瞎子對大象的認(rèn)識(shí)不同,因?yàn)樗麄冎徽J(rèn)識(shí)了自己摸到的地方。而企業(yè)如果要避免重犯這樣的錯(cuò)誤,那就離不開商務(wù)智能(BI)。專家認(rèn)為,BI對于企業(yè)的重要性就像聰明才智對于個(gè)人的重要性。歐美企業(yè)的經(jīng)驗(yàn)也證明,企業(yè)避免無知和一知半解危險(xiǎn)的有效手段就是商務(wù)智能。商務(wù)智能旨在充分利用企業(yè)在日常經(jīng)營過程中收集的大量數(shù)據(jù)和資料,并將它們轉(zhuǎn)化為信息和知識(shí)來免除各種無知狀態(tài)和瞎猜行為。   

          支持BI的開源工具數(shù)量眾多,但是大多數(shù)的工具都是偏重某方面的。例如,CloverETL偏重ETL,JPivot偏重多維分析展現(xiàn),Mondrian是OLAP服務(wù)器。而Bee、Pentaho和SpagoBI等項(xiàng)目則針對商務(wù)智能問題提供了完整的解決方案。

          ETL 工具

          ETL開源工具主要包括CloverETL和Octupus等。

          (1)CloverETL是一個(gè)Java的ETL框架,用來轉(zhuǎn)換結(jié)構(gòu)化的數(shù)據(jù),支持多種字符集之間的轉(zhuǎn)換(如ASCII、UTF-8和ISO-8859-1等);支持JDBC,同時(shí)支持dBase和FoxPro數(shù)據(jù)文件;支持基于XML的轉(zhuǎn)換描述。

          (2)Octupus是一個(gè)基于Java的ETL工具,它也支持JDBC數(shù)據(jù)源和基于XML的轉(zhuǎn)換定義。Octupus提供通用的方法進(jìn)行數(shù)據(jù)轉(zhuǎn)換,用戶可以通過實(shí)現(xiàn)轉(zhuǎn)換接口或者使用Jscript代碼來定義轉(zhuǎn)換流程。

          OLAP服務(wù)器

          (1)Lemur主要面向HOLAP,雖然采用C++編寫,但是可以被其他語言的程序所調(diào)用。Lemur支持基本的操作,如切片、切塊和旋轉(zhuǎn)等基本操作。

          (2)Mondrian面向ROLAP包含4層:表示層、計(jì)算層、聚集層、存儲(chǔ)層。

          ● 表示層:指最終呈現(xiàn)在用戶顯示器上的以及與用戶之間的交互,有許多方法來展現(xiàn)多維數(shù)據(jù),包括數(shù)據(jù)透視表、餅、柱、線狀圖。

          ● 計(jì)算層:分析、驗(yàn)證、執(zhí)行MDX查詢。

          ● 聚集層:一個(gè)聚集指內(nèi)存中一組計(jì)算值(cell),這些值通過維列來限制。計(jì)算層發(fā)送單元請求,如果請求不在緩存中,或者不能通過旋轉(zhuǎn)聚集導(dǎo)出的話,那么聚集層向存儲(chǔ)層發(fā)送請求。聚合層是一個(gè)數(shù)據(jù)緩沖層,從數(shù)據(jù)庫來的單元數(shù)據(jù),聚合后提供給計(jì)算層。聚合層的主要作用是提高系統(tǒng)的性能。

          ● 存儲(chǔ)層:提供聚集單元數(shù)據(jù)和維表的成員。包括三種需要存儲(chǔ)的數(shù)據(jù),分別是事實(shí)數(shù)據(jù)、聚集和維。

          OLAP客戶端

          JPivot是JSP風(fēng)格的標(biāo)簽庫,用來支持OLAP表,使用戶可以執(zhí)行典型的OLAP操作,如切片、切塊、上鉆、下鉆等。JPivot使用Mondrian服務(wù)器,分析結(jié)果可以導(dǎo)出為Excel或PDF文件格式。

          數(shù)據(jù)庫管理系統(tǒng)

          主要的開源工具包括MonetDB、MySQL、MaxDB和PostgreSQL等。這些數(shù)據(jù)庫都被設(shè)計(jì)用來支持BI環(huán)境。MySQL、MaxDB和PostgreSQL均支持單向的數(shù)據(jù)復(fù)制。BizGres項(xiàng)目的目的在于使PostgreSQL成為數(shù)據(jù)倉庫和 BI的開源標(biāo)準(zhǔn)。BizGres為BI環(huán)境構(gòu)建專用的完整數(shù)據(jù)庫平臺(tái)。

          完整的BI開源解決方案

          1.Pentaho 公司的Pentaho BI 平臺(tái)

          它是一個(gè)以流程為中心的、面向解決方案的框架,具有商務(wù)智能組件。BI 平臺(tái)是以流程為中心的,其中樞控制器是一個(gè)工作流引擎。工作流引擎使用流程定義來定義在 BI 平臺(tái)上執(zhí)行的商務(wù)智能流程。流程可以很容易被定制,也可以添加新的流程。BI 平臺(tái)包含組件和報(bào)表,用以分析這些流程的性能。BI 平臺(tái)是面向解決方案的,平臺(tái)的操作是定義在流程定義和指定每個(gè)活動(dòng)的 action 文檔里。這些流程和操作共同定義了一個(gè)商務(wù)智能問題的解決方案。這個(gè) BI 解決方案可以很容易地集成到平臺(tái)外部的商業(yè)流程。一個(gè)解決方案的定義可以包含任意數(shù)量的流程和操作。

          BI平臺(tái)包括一個(gè) BI 框架、BI 組件、一個(gè) BI 工作臺(tái)和桌面收件箱。BI 工作臺(tái)是一套設(shè)計(jì)和管理工具,集成到Eclipse環(huán)境。這些工具允許商業(yè)分析人員或開發(fā)人員創(chuàng)建報(bào)表、儀表盤、分析模型、商業(yè)規(guī)則和 BI 流程。Pentaho BI 平臺(tái)構(gòu)建于服務(wù)器、引擎和組件的基礎(chǔ)之上,包括J2EE 服務(wù)器、安全與權(quán)限控制、portal、工作流、規(guī)則引擎、圖表、協(xié)作、內(nèi)容管理、數(shù)據(jù)集成、多維分析和系統(tǒng)建模等功能。這些組件的大部分是基于標(biāo)準(zhǔn)的,可使用其他產(chǎn)品替換之。

          2.ObjectWeb

          該項(xiàng)目近日發(fā)布了SpagoBi 1.8版本。SpagoBi 是一款基于Mondrain+JProvit的BI方案,能夠通過OpenLaszlo產(chǎn)生實(shí)時(shí)報(bào)表,為商務(wù)智能項(xiàng)目提供了一個(gè)完整開源的解決方案,它涵蓋了一個(gè)BI系統(tǒng)所有方面的功能,包括:數(shù)據(jù)挖掘、查詢、分析、報(bào)告、Dashboard儀表板等等。SpagoBI使用核心系統(tǒng)與功能模塊集成的架構(gòu),這樣在確保平臺(tái)穩(wěn)定性與協(xié)調(diào)性的基礎(chǔ)上又保證了系統(tǒng)具有很強(qiáng)的擴(kuò)展能力。用戶無需使用SpagoBI的所有模塊,而是可以只利用其中的一些模塊。

          SpagoBI使用了許多已有的開源軟件,如Spago和Spagosi等。因此,SpagoBI集成了 Spago的特征和技術(shù)特點(diǎn),使用它們管理商務(wù)智能對象,如報(bào)表、OLAP分析、儀表盤、記分卡以及數(shù)據(jù)挖掘模型等。SpagoBI支持BI系統(tǒng)的監(jiān)控管理,包括商務(wù)智能對象的控制、校驗(yàn)、認(rèn)證和分配流程。SpagoBI采用Portalet技術(shù)將所有的BI對象發(fā)布到終端用戶,因此BI對象就可以集成到為特定的企業(yè)需求而已經(jīng)選擇好的Portal系統(tǒng)中去。

          3.Bee項(xiàng)目

          該項(xiàng)目是一套支持商務(wù)智能項(xiàng)目實(shí)施的工具套件,包括ETL工具和OLAP 服務(wù)器。Bee的ETL工具使用基于Perl的BEI,通過界面描述流程,以XML形式進(jìn)行存儲(chǔ)。用戶必須對轉(zhuǎn)換過程進(jìn)行編碼。Bee的ROLAP 服務(wù)器保證多通SQL 生成和強(qiáng)有力的高速緩存管理(使用MySQL數(shù)據(jù)庫管理系統(tǒng))。ROLAP服務(wù)器通過SOAP應(yīng)用接口提供豐富的客戶應(yīng)用。Web Portal作為主要的用戶接口,通過Web瀏覽器進(jìn)行報(bào)表設(shè)計(jì)、展示和管理控制,分析結(jié)果可以以Excel、PDF、PNG、PowerPoint、 text和XML等多種形式導(dǎo)出。

          Bee項(xiàng)目的特點(diǎn)在于:

          ● 簡單快捷的數(shù)據(jù)訪問;

          ● 支持預(yù)先定義報(bào)表和實(shí)時(shí)查詢;

          ● 通過拖拽方式輕松實(shí)現(xiàn)報(bào)表定制;

          ● 完整報(bào)表的輕松控制;

          ● 以表和圖進(jìn)行高質(zhì)量的數(shù)據(jù)展示。

          posted @ 2008-02-23 23:29 edsonjava 閱讀(533) | 評論 (0)編輯 收藏
           
          java /zongfeng 
          mondrian是一個(gè)olap工具,jpviot是一個(gè)顯示它處理結(jié)果的taglib,使用這2個(gè)工具可以做復(fù)雜的統(tǒng)計(jì)匯總并顯示

          OLAP:Mondrian&JPviot


          olap:online analytical processing(聯(lián)機(jī)分析處理),實(shí)時(shí)的分析大量數(shù)據(jù),其操作通常是 只讀的.online意味著即使是大量的數(shù)據(jù),系統(tǒng)對查詢的響應(yīng)也要足夠快.

          olap使用一種技術(shù)叫做multimensional analysis(多維分析),關(guān)系數(shù)據(jù)庫將數(shù)據(jù)存成行和列的形式,多維數(shù)據(jù)表包含軸和單元.

          mondrian包含4層:表示層,計(jì)算層,聚集層,存儲(chǔ)層.

          表示層:指最終呈現(xiàn)在用戶顯示器上的,以及與用戶之間的交互,有許多方法來展現(xiàn)多維數(shù)據(jù),包括數(shù)據(jù)透視表,餅,柱,線狀圖.

          計(jì)算層:分析,驗(yàn)證,執(zhí)行MDX查詢.

          聚集層:一個(gè)聚集指內(nèi)存中一組計(jì)算值(cell),這些值通過維列來限制.計(jì)算層發(fā)送單元請求,如果請求不在緩存中,或者不能通過旋轉(zhuǎn)聚集導(dǎo)出的話,聚集層向存儲(chǔ)層發(fā)送請求.

          聚合層是一個(gè)數(shù)據(jù)緩沖層,從數(shù)據(jù)庫來的單元數(shù)據(jù),聚合后提供給計(jì)算層。聚合層的主要作用是提高系統(tǒng)的性能。

          存儲(chǔ)層:提供聚集單元數(shù)據(jù)和維表的成員,這些層可以不在同一機(jī)子上,但是計(jì)算和聚集層必須在同一臺(tái)機(jī)子上.

          三種需要存儲(chǔ)的數(shù)據(jù):1:事實(shí)數(shù)據(jù)2:聚集3:維

          配置文件中的特定含義:
          1:cube(立方體):是維和量的集合

          2:measure(量):一個(gè)具體的測量量

          3:dimension(維):一個(gè)屬性或者一系列屬性,通過維可以將量分類

          下面是我關(guān)于jpviot的修改:jpviot是顯示mondrian的一個(gè)taglib

          問題1:讓行和列的標(biāo)題顯示為中文,此問題非常簡單,只需要在你的schema中設(shè)置一下編碼即可,例如在FoodMart中設(shè)置如下

          <?xml version="1.0" encoding="gb2312"?>

          然后可以這樣描述Measure:

          <Measure name="庫存消耗" column="store_cost" aggregator="sum" formatString="#,###.00"/>

          所有帶name屬性的都可以替換成中文,jpviot會(huì)自動(dòng)顯示這些中文.

          問題2:關(guān)于去掉Measure標(biāo)題的問題:

          默認(rèn)生成的報(bào)表中會(huì)有這么一行
          <tr>
          <th rowspan="1" colspan="2" class="corner-heading" nowrap="nowrap">&nbsp;</th><th rowspan="1" colspan="3" class="heading-heading" nowrap="nowrap"><img height="9" width="9" border="0" src="/jpivot/jpivot/table/drill-position-other.gif">Measures</th>
          </tr>

          這一行有個(gè)默認(rèn)的標(biāo)題是Measure,如果你不想刪除這一行,而僅僅想修改這個(gè)標(biāo)題的話,可以修改
          WEB-INFclassescomtonbellerjpivotmondrianresources.properties.但是注意這個(gè)文件中內(nèi)容寫成英文沒問題,如寫成中文的話應(yīng)該寫成unicode,例如023這樣的形式.

          如果你要去掉這一行的話,修改配置文件和xsl恐怕做不到,我分析了其代碼,最終在代碼層次上做了修改:
          修改的代碼為com.tonbeller.jpivot.table.ColumnAxisBuilderImpl:

          將其構(gòu)造函數(shù)中的setHierarchyHeader的參數(shù)修改為setHierarchyHeader(NO_HEADER);這個(gè)函數(shù)支持3個(gè)參數(shù),我們修改后就不會(huì)顯示那個(gè)標(biāo)題行了.

          問題3:生成圖表后自動(dòng)生成chart表的問題:

          我測試生成圖表中的中文問題都解決了,但是每次生成chart圖時(shí)會(huì)報(bào)UTF編碼錯(cuò)誤,從錯(cuò)誤判斷應(yīng)該是某個(gè)文件的編碼錯(cuò)誤,起初根據(jù)錯(cuò)誤判斷是filter的問題,可是filter那點(diǎn)代碼中根本不涉及編碼的問題.我將很多配置文件的編碼都改了也不行.因?yàn)槟莻€(gè)英文例子沒問題,我查看了JFreechart的一個(gè)servlet(org.jfree.chart.servlet.DisplayChart),因?yàn)閖pviot就是調(diào)用這個(gè)servlet實(shí)現(xiàn)繪圖的,分析這個(gè)servlet我知道它會(huì)在一個(gè)臨時(shí)目錄生成png文件,然后交給servlet寫到瀏覽器的響應(yīng)中去,我找到那個(gè)臨時(shí)目錄(tomcattemp),發(fā)現(xiàn)里面已經(jīng)生成了正確的中文圖形.從而判斷圖形生成正確,但是寫到瀏覽器中時(shí)出了問題.最后我查看能生成英文圖表的那個(gè)例子,發(fā)覺不僅僅在html中生成圖形,而且生成map.而這個(gè)map的生成全是在程序中做的,程序生成一個(gè)xml文件,通過chart.xsl解析生成map的最終html代碼.但是在程序中生成時(shí)并沒有加入編碼設(shè)置,因此問題出在生成map這兒.

          最終修改代碼如下:

          com.tonbeller.jpivot.chart.ChartComponent:

          在render函數(shù)中修改如下:

          String desc="<?xml version="1.0" encoding="gb2312"?>";
          String xchart =desc+"n"+ "<xchart>" + writeImageMap(filename, info, false) + "</xchart>";
          這樣就為xchart設(shè)置了編碼.

          問題4:修改jfreechart中的默認(rèn)字體:

          com.tonbeller.jpivot.chart.ChartComponent中定義了幾種字體,但是這幾種字體都是英文字體,我將其修改為宋體:
          把所有的字體定義都改為"SimSun"
          注意到這兒并沒有玩,如果你僅僅修改程序,仍舊會(huì)出現(xiàn)問題,報(bào)錯(cuò)說沒有適合"SimSun"的item
          同時(shí)要修改一個(gè)配置文件:WEB-INFjpivotchartchartpropertiesform.xml
          在這個(gè)配置文件中將SimSun加入其中,形式如下:

          <listBox1 type="string" modelReference="fontName" label="Title font">
          <listItem value="SansSerif" label="SansSerif"/>
          <listItem value="Serif" label="Serif"/>
          <listItem value="SimSun" label="SimSun"/>
          <listItem value="Monospaced" label="Monospaced"/>
          </listBox1>

          以上為我最近的一點(diǎn)心得,我會(huì)完善這篇文檔,將包含mondrian中schema的書寫方法和MDX查詢語言,歡迎大家交流
          link1:微軟的MDX中文文檔

          posted @ 2008-02-23 23:20 edsonjava 閱讀(884) | 評論 (0)編輯 收藏
           

          在xml應(yīng)用中,經(jīng)常將一些URL信息作為xml數(shù)據(jù)存儲(chǔ),其中URL參數(shù)有可能包含有中文字符。
          當(dāng)使用dom對xml數(shù)據(jù)進(jìn)行解析時(shí),可以對中文字符進(jìn)行編碼。
          但如果只使用xslt來顯示xml數(shù)據(jù)時(shí)(data.xml+data.xsl),發(fā)現(xiàn)此時(shí)的URL會(huì)出現(xiàn)編碼錯(cuò)誤.
          即使指定編碼類型(encoding="gb2312"),依然會(huì)出現(xiàn)同樣的問題.
          測試發(fā)現(xiàn):是IE的緩存機(jī)制問題,IE仍會(huì)把新的頁面(所鏈接的URL)的MIME內(nèi)容類型默認(rèn)為text/xml

          解決方法:
          1.指定輸出文檔類型為xml文檔  (example:data.xsl)
           <xsl:output method="xml"  encoding="gb2312" media-type="text/xml" />
          2.在新的窗口打開,給聯(lián)接增加屬性,指明目標(biāo)窗口為其他窗口  (example:data2.xsl)
           <xsl:attribute name="target">_blank</xsl:attribute>


          examples:


          /*** data.xml ***/

          <?xml version="1.0" encoding="gb2312"?>
          <?xml-stylesheet type="text/xsl" href="data.xsl"?>
          <root>
           <search>
            <url>http://www.google.com/search?q=</url>
            <word>xml數(shù)據(jù)</word>
           </search>
           <search>
            <url>http://www1.baidu.com/baidu?word=</url>
            <word>xml數(shù)據(jù)</word>
           </search>
           <search>
            <url>http://www.google.com/search?q=</url>
            <word>極限編程(xp)</word>
           </search>
           <search>
            <url>http://www1.baidu.com/baidu?word=</url>
            <word>極限編程(xp)</word>
           </search>
          </root>


          /*** data.xsl ***/

          <?xml version="1.0" encoding="gb2312"?>
          <xsl:stylesheet version="1.0" xmlns:xsl=" <!-- 去掉下面一句,將出現(xiàn)錯(cuò)誤 -->
          <xsl:output method="xml"  encoding="gb2312" media-type="text/xml" />

          <xsl:template match="/">
           <xsl:apply-templates /> 
          </xsl:template>

          <xsl:template match="search">
           <xsl:element name="a">
            <xsl:attribute name="href"><xsl:value-of select="url" /><xsl:value-of select="word" /></xsl:attribute>
            <xsl:value-of select="word" />
           </xsl:element>
           <br />
          </xsl:template>

          </xsl:stylesheet>


          /*** data2.xsl ***/

          <?xml version="1.0" encoding="gb2312"?>
          <xsl:stylesheet version="1.0" xmlns:xsl="

          <xsl:template match="/">
           <xsl:apply-templates /> 
          </xsl:template>

          <xsl:template match="search">
           <xsl:element name="a">
            <xsl:attribute name="href"><xsl:value-of select="url" /><xsl:value-of select="word" /></xsl:attribute>
            <!-- 去掉下面一句,將出現(xiàn)錯(cuò)誤 -->
            <xsl:attribute name="target">_blank</xsl:attribute>
            <xsl:value-of select="word" />
           </xsl:element>
           <br />
          </xsl:template>

          </xsl:stylesheet>

          posted @ 2008-02-23 23:08 edsonjava 閱讀(531) | 評論 (0)編輯 收藏
           
          軟件包:javax.servlet.http 
                所包含的接口:HttpServletRequest;HttpServletResponse;HttpSession;HttpSessionBindingListener;HttpSessionContext。
                所包含的類:Cookie;HttpServlet;HttpSessionBindingEvent;HttpUtils。

                一、HttpServletRequest接口
                定義\
                public interface HttpServletRequest extends ServletRequest;
                用來處理一個(gè)對Servlet的HTTP格式的請求信息。
                方法
                1、getAuthType
                public String getAuthType();
                返回這個(gè)請求的身份驗(yàn)證模式。
                2、getCookies
                public Cookie[] getCookies();
                返回一個(gè)數(shù)組,該數(shù)組包含這個(gè)請求中當(dāng)前的所有cookie。如果這個(gè)請求中沒有cookie,返回一個(gè)空數(shù)組。
                3、getDateHeader
                public long getDateHeader(String name);
                返回指定的請求頭域的值,這個(gè)值被轉(zhuǎn)換成一個(gè)反映自1970-1-1日(GMT)以來的精確到毫秒的長整數(shù)。
                如果頭域不能轉(zhuǎn)換,拋出一個(gè)IllegalArgumentException。如果這個(gè)請求頭域不存在,這個(gè)方法返回-1。
                4、getHeader
                public String getHeader(String name);
                返回一個(gè)請求頭域的值。(譯者注:與上一個(gè)方法不同的是,該方法返回一個(gè)字符串)
                如果這個(gè)請求頭域不存在,這個(gè)方法返回-1。
                5、getHeaderNames
                public Enumeration getHeaderNames();
                該方法返回一個(gè)String對象的列表,該列表反映請求的所有頭域名。
                有的引擎可能不允許通過這種方法訪問頭域,在這種情況下,這個(gè)方法返回一個(gè)空的列表。
                6、getIntHeader
                public int getIntHeader(String name);
                返回指定的請求頭域的值,這個(gè)值被轉(zhuǎn)換成一個(gè)整數(shù)。
                如果頭域不能轉(zhuǎn)換,拋出一個(gè)IllegalArgumentException。如果這個(gè)請求頭域不存在,這個(gè)方法返回-1。
                7、getMethod
                public String getMethod();
                返回這個(gè)請求使用的HTTP方法(例如:GET、POST、PUT)
                8、getPathInfo
                public String getPathInfo();
                這個(gè)方法返回在這個(gè)請求的URL的Servlet路徑之后的請求URL的額外的路徑信息。如果這個(gè)請求URL包括一個(gè)查詢字符串,在返回值內(nèi)將不包括這個(gè)查詢字符串。這個(gè)路徑在返回之前必須經(jīng)過URL解碼。如果在這個(gè)請求的URL的Servlet路徑之后沒有路徑信息。這個(gè)方法返回空值。
                9、getPathTranslated
                public String getPathTranslated();
                這個(gè)方法獲得這個(gè)請求的URL的Servlet路徑之后的額外的路徑信息,并將它轉(zhuǎn)換成一個(gè)真實(shí)的路徑。在進(jìn)行轉(zhuǎn)換前,這個(gè)請求的URL必須經(jīng)過URL解碼。如果在這個(gè)URL的Servlet路徑之后沒有附加路徑信息。這個(gè)方法返回空值。
                10、getQueryString
                public String getQueryString();
                返回這個(gè)請求URL所包含的查詢字符串。一個(gè)查詢字串符在一個(gè)URL中由一個(gè)“?”引出。如果沒有查詢字符串,這個(gè)方法返回空值。
                11、getRemoteUser
                public String getRemoteUser
                返回作了請求的用戶名,這個(gè)信息用來作HTTP用戶論證。
                如果在請求中沒有用戶名信息,這個(gè)方法返回空值。
                12、getRequestedSessionId
                public String getRequestedSessionId();
                返回這個(gè)請求相應(yīng)的session id。如果由于某種原因客戶端提供的session id是無效的,這個(gè)session id將與在當(dāng)前session中的session id不同,與此同時(shí),將建立一個(gè)新的session。
                如果這個(gè)請求沒與一個(gè)session關(guān)聯(lián),這個(gè)方法返回空值。
                13、getRequestURI
                public String getRequestURI();
                從HTTP請求的第一行返回請求的URL中定義被請求的資源的部分。如果有一個(gè)查詢字符串存在,這個(gè)查詢字符串將不包括在返回值當(dāng)中。例如,一個(gè)請求通過/catalog/books?id=1這樣的URL路徑訪問,這個(gè)方法將返回/catalog/books。這個(gè)方法的返回值包括了Servlet路徑和路徑信息。
                如果這個(gè)URL路徑中的的一部分經(jīng)過了URL編碼,這個(gè)方法的返回值在返回之前必須經(jīng)過解碼。
                14、getServletPath
                public String getServletPath();
                這個(gè)方法返回請求URL反映調(diào)用Servlet的部分。例如,一個(gè)Servlet被映射到/catalog/summer這個(gè)URL路徑,而一個(gè)請求使用了/catalog/summer/casual這樣的路徑。所謂的反映調(diào)用Servlet的部分就是指/catalog/summer。
                如果這個(gè)Servlet不是通過路徑匹配來調(diào)用。這個(gè)方法將返回一個(gè)空值。
                15、getSession
                public HttpSession getSession();
                public HttpSession getSession(boolean create);
                返回與這個(gè)請求關(guān)聯(lián)的當(dāng)前的有效的session。如果調(diào)用這個(gè)方法時(shí)沒帶參數(shù),那么在沒有session與這個(gè)請求關(guān)聯(lián)的情況下,將會(huì)新建一個(gè)session。如果調(diào)用這個(gè)方法時(shí)帶入了一個(gè)布爾型的參數(shù),只有當(dāng)這個(gè)參數(shù)為真時(shí),session才會(huì)被建立。
                為了確保session能夠被完全維持。Servlet開發(fā)者必須在響應(yīng)被提交之前調(diào)用該方法。
                如果帶入的參數(shù)為假,而且沒有session與這個(gè)請求關(guān)聯(lián)。這個(gè)方法會(huì)返回空值。
                16、isRequestedSessionIdValid
                public boolean isRequestedSessionIdValid();
                這個(gè)方法檢查與此請求關(guān)聯(lián)的session當(dāng)前是不是有效。如果當(dāng)前請求中使用的session無效,它將不能通過getSession方法返回。
                17、isRequestedSessionIdFromCookie
                public boolean isRequestedSessionIdFromCookie();
                如果這個(gè)請求的session id是通過客戶端的一個(gè)cookie提供的,該方法返回真,否則返回假。
                18、isRequestedSessionIdFromURL
                public boolean isRequestedSessionIdFromURL();
                如果這個(gè)請求的session id是通過客戶端的URL的一部分提供的,該方法返回真,否則返回假。請注意此方法與isRequestedSessionIdFromUrl在URL的拼寫上不同。
                以下方法將被取消\

                19、isRequestedSessionIdFromUrl
                public boolean isRequestedSessionIdFromUrl();
                該方法被isRequestedSessionIdFromURL代替。

                二、HttpServletResponse接口
                定義\

                public interface HttpServletResponse extends ServletResponse
                描述一個(gè)返回到客戶端的HTTP回應(yīng)。這個(gè)接口允許Servlet程序員利用HTTP協(xié)議規(guī)定的頭信息。
                成員變量
                public static final int SC_CONTINUE = 100;
                public static final int SC_SWITCHING_PROTOCOLS = 101;
                public static final int SC_OK = 200;
                public static final int SC_CREATED = 201;
                public static final int SC_ACCEPTED = 202;
                public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
                public static final int SC_NO_CONTENT = 204;
                public static final int SC_RESET_CONTENT = 205;
                public static final int SC_PARTIAL_CONTENT = 206;
                public static final int SC_MULTIPLE_CHOICES = 300;
                public static final int SC_MOVED_PERMANENTLY = 301;
                public static final int SC_MOVED_TEMPORARILY = 302;
                public static final int SC_SEE_OTHER = 303;
                public static final int SC_NOT_MODIFIED = 304;
                public static final int SC_USE_PROXY = 305;
                public static final int SC_BAD_REQUEST = 400;
                public static final int SC_UNAUTHORIZED = 401;
                public static final int SC_PAYMENT_REQUIRED = 402;
                public static final int SC_FORBIDDEN = 403;
                public static final int SC_NOT_FOUND = 404;
                public static final int SC_METHOD_NOT_ALLOWED = 405;
                public static final int SC_NOT_ACCEPTABLE = 406;
                public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
                public static final int SC_REQUEST_TIMEOUT = 408;
                public static final int SC_CONFLICT = 409;
                public static final int SC_GONE = 410;
                public static final int SC_LENGTH_REQUIRED = 411;
                public static final int SC_PRECONDITION_FAILED = 412;
                public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
                public static final int SC_REQUEST_URI_TOO_LONG = 414;
                public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
                public static final int SC_INTERNAL_SERVER_ERROR = 500;
                public static final int SC_NOT_IMPLEMENTED = 501;
                public static final int SC_BAD_GATEWAY = 502;
                public static final int SC_SERVICE_UNAVAILABLE = 503;
                public static final int SC_GATEWAY_TIMEOUT = 504;
                public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
                以上HTTP產(chǎn)狀態(tài)碼是由HTTP/1.1定義的。
                方法
                1、addCookie
                public void addCookie(Cookie cookie);
                在響應(yīng)中增加一個(gè)指定的cookie。可多次調(diào)用該方法以定義多個(gè)cookie。為了設(shè)置適當(dāng)?shù)念^域,該方法應(yīng)該在響應(yīng)被提交之前調(diào)用。
                2、containsHeader
                public boolean containsHeader(String name);
                檢查是否設(shè)置了指定的響應(yīng)頭。
                3、encodeRedirectURL
                public String encodeRedirectURL(String url);
                對sendRedirect方法使用的指定URL進(jìn)行編碼。如果不需要編碼,就直接返回這個(gè)URL。之所以提供這個(gè)附加的編碼方法,是因?yàn)樵趓edirect的情況下,決定是否對URL進(jìn)行編碼的規(guī)則和一般情況有所不同。所給的URL必須是一個(gè)絕對URL。相對URL不能被接收,會(huì)拋出一個(gè)IllegalArgumentException。
                所有提供給sendRedirect方法的URL都應(yīng)通過這個(gè)方法運(yùn)行,這樣才能確保會(huì)話跟蹤能夠在所有瀏覽器中正常運(yùn)行。
                4、encodeURL
                public String encodeURL(String url);
                對包含session ID的URL進(jìn)行編碼。如果不需要編碼,就直接返回這個(gè)URL。Servlet引擎必須提供URL編碼方法,因?yàn)樵谟行┣闆r下,我們將不得不重寫URL,例如,在響應(yīng)對應(yīng)的請求中包含一個(gè)有效的session,但是這個(gè)session不能被非URL的(例如cookie)的手段來維持。
                所有提供給Servlet的URL都應(yīng)通過這個(gè)方法運(yùn)行,這樣才能確保會(huì)話跟蹤能夠在所有瀏覽器中正常運(yùn)行。
                5、sendError
                public void sendError(int statusCode) throws IOException;
                public void sendError(int statusCode, String message) throws
                   IOException;
                用給定的狀態(tài)碼發(fā)給客戶端一個(gè)錯(cuò)誤響應(yīng)。如果提供了一個(gè)message參數(shù),這將作為響應(yīng)體的一部分被發(fā)出,否則,服務(wù)器會(huì)返回錯(cuò)誤代碼所對應(yīng)的標(biāo)準(zhǔn)信息。
                調(diào)用這個(gè)方法后,響應(yīng)立即被提交。在調(diào)用這個(gè)方法后,Servlet不會(huì)再有更多的輸出。
                6、sendRedirect
                public void sendRedirect(String location) throws IOException;
                使用給定的路徑,給客戶端發(fā)出一個(gè)臨時(shí)轉(zhuǎn)向的響應(yīng)(SC_MOVED_TEMPORARILY)。給定的路徑必須是絕對URL。相對URL將不能被接收,會(huì)拋出一個(gè)IllegalArgumentException。
                這個(gè)方法必須在響應(yīng)被提交之前調(diào)用。調(diào)用這個(gè)方法后,響應(yīng)立即被提交。在調(diào)用這個(gè)方法后,Servlet不會(huì)再有更多的輸出。
                7、setDateHeader
                public void setDateHeader(String name, long date);
                用一個(gè)給定的名稱和日期值設(shè)置響應(yīng)頭,這里的日期值應(yīng)該是反映自1970-1-1日(GMT)以來的精確到毫秒的長整數(shù)。如果響應(yīng)頭已經(jīng)被設(shè)置,新的值將覆蓋當(dāng)前的值。
                8、setHeader
                public void setHeader(String name, String value);
                用一個(gè)給定的名稱和域設(shè)置響應(yīng)頭。如果響應(yīng)頭已經(jīng)被設(shè)置,新的值將覆蓋當(dāng)前的值。
                9、setIntHeader
                public void setIntHeader(String name, int value);
                用一個(gè)給定的名稱和整形值設(shè)置響應(yīng)頭。如果響應(yīng)頭已經(jīng)被設(shè)置,新的值將覆蓋當(dāng)前的值。
                10、setStatus
                public void setStatus(int statusCode);
                這個(gè)方法設(shè)置了響應(yīng)的狀態(tài)碼,如果狀態(tài)碼已經(jīng)被設(shè)置,新的值將覆蓋當(dāng)前的值。
                以下的幾個(gè)方法將被取消\
                11、encodeRedirectUrl
                public String encodeRedirectUrl(String url);
                該方法被encodeRedirectURL取代。 
                12、encodeUrl
                public String encodeUrl(String url);
                該方法被encodeURL取代。 
                13、setStatus
                public void setStatus(int statusCode, String message);
                這個(gè)方法設(shè)置了響應(yīng)的狀態(tài)碼,如果狀態(tài)碼已經(jīng)被設(shè)置,新的值將覆蓋當(dāng)前的值。如果提供了一個(gè)message,它也將會(huì)被作為響應(yīng)體的一部分被發(fā)送。

                三、HttpSession接口
                定義\
                public interface HttpSession
                這個(gè)接口被Servlet引擎用來實(shí)現(xiàn)在HTTP客戶端和HTTP會(huì)話兩者的關(guān)聯(lián)。這種關(guān)聯(lián)可能在多外連接和請求中持續(xù)一段給定的時(shí)間。session用來在無狀態(tài)的HTTP協(xié)議下越過多個(gè)請求頁面來維持狀態(tài)和識(shí)別用戶。
                一個(gè)session可以通過cookie或重寫URL來維持。
                方法
                1、getCreationTime
                public long getCreationTime();
                返回建立session的時(shí)間,這個(gè)時(shí)間表示為自1970-1-1日(GMT)以來的毫秒數(shù)。 
                2、getId
                public String getId();
                返回分配給這個(gè)session的標(biāo)識(shí)符。一個(gè)HTTP session的標(biāo)識(shí)符是一個(gè)由服務(wù)器來建立和維持的唯一的字符串。
                3、getLastAccessedTime
                public long getLastAccessedTime();
                返回客戶端最后一次發(fā)出與這個(gè)session有關(guān)的請求的時(shí)間,如果這個(gè)session是新建立的,返回-1。這個(gè)時(shí)間表示為自1970-1-1日(GMT)以來的毫秒數(shù)。 
                4、getMaxInactiveInterval
                public int getMaxInactiveInterval();
                返加一個(gè)秒數(shù),這個(gè)秒數(shù)表示客戶端在不發(fā)出請求時(shí),session被Servlet引擎維持的最長時(shí)間。在這個(gè)時(shí)間之后,Servlet引擎可能被Servlet引擎終止。如果這個(gè)session不會(huì)被終止,這個(gè)方法返回-1。
                當(dāng)session無效后再調(diào)用這個(gè)方法會(huì)拋出一個(gè)IllegalStateException。
                5、getValue
                public Object getValue(String name);
                返回一個(gè)以給定的名字綁定到session上的對象。如果不存在這樣的綁定,返回空值。
                當(dāng)session無效后再調(diào)用這個(gè)方法會(huì)拋出一個(gè)IllegalStateException。
                6、getValueNames
                public String[] getValueNames();
                以一個(gè)數(shù)組返回綁定到session上的所有數(shù)據(jù)的名稱。
                當(dāng)session無效后再調(diào)用這個(gè)方法會(huì)拋出一個(gè)IllegalStateException。
                7、invalidate
                public void invalidate();
                這個(gè)方法會(huì)終止這個(gè)session。所有綁定在這個(gè)session上的數(shù)據(jù)都會(huì)被清除。并通過HttpSessionBindingListener接口的valueUnbound方法發(fā)出通告。
                8、isNew
                public boolean isNew();
                返回一個(gè)布爾值以判斷這個(gè)session是不是新的。如果一個(gè)session已經(jīng)被服務(wù)器建立但是還沒有收到相應(yīng)的客戶端的請求,這個(gè)session將被認(rèn)為是新的。這意味著,這個(gè)客戶端還沒有加入會(huì)話或沒有被會(huì)話公認(rèn)。在他發(fā)出下一個(gè)請求時(shí)還不能返回適當(dāng)?shù)膕ession認(rèn)證信息。
                當(dāng)session無效后再調(diào)用這個(gè)方法會(huì)拋出一個(gè)IllegalStateException。
                9、putValue
                public void putValue(String name, Object value);
                以給定的名字,綁定給定的對象到session中。已存在的同名的綁定會(huì)被重置。這時(shí)會(huì)調(diào)用HttpSessionBindingListener接口的valueBound方法。
                當(dāng)session無效后再調(diào)用這個(gè)方法會(huì)拋出一個(gè)IllegalStateException。
                10、removeValue
                public void removeValue(String name);
                取消給定名字的對象在session上的綁定。如果未找到給定名字的綁定的對象,這個(gè)方法什么出不做。 這時(shí)會(huì)調(diào)用HttpSessionBindingListener接口的valueUnbound方法。
                當(dāng)session無效后再調(diào)用這個(gè)方法會(huì)拋出一個(gè)IllegalStateException。
                11、setMaxInactiveInterval
                public int setMaxInactiveInterval(int interval);
                設(shè)置一個(gè)秒數(shù),這個(gè)秒數(shù)表示客戶端在不發(fā)出請求時(shí),session被Servlet引擎維持的最長時(shí)間。
                以下這個(gè)方法將被取消\
                12、getSessionContext
                public HttpSessionContext getSessionContext();
                返回session在其中得以保持的環(huán)境變量。這個(gè)方法和其他所有HttpSessionContext的方法一樣被取消了。

                四、HttpSessionBindingListener接口
                定義\
                public interface HttpSessionBindingListener
                這個(gè)對象被加入到HTTP的session中,執(zhí)行這個(gè)接口會(huì)通告有沒有什么對象被綁定到這個(gè)HTTP session中或被從這個(gè)HTTP session中取消綁定。
                方法
                1、valueBound
                public void valueBound(HttpSessionBindingEvent event);
                當(dāng)一個(gè)對象被綁定到session中,調(diào)用此方法。HttpSession.putValue方法被調(diào)用時(shí),Servlet引擎應(yīng)該調(diào)用此方法。
                2、valueUnbound
                public void valueUnbound(HttpSessionBindingEvent event);
                當(dāng)一個(gè)對象被從session中取消綁定,調(diào)用此方法。HttpSession.removeValue方法被調(diào)用時(shí),Servlet引擎應(yīng)該調(diào)用此方法。

                五、HttpSessionContext接口
                定義\
                此接口將被取消\
                public interface HttpSessionContext
                這個(gè)對象是與一組HTTP session關(guān)聯(lián)的單一的實(shí)體。
                這個(gè)接口由于安全的原因被取消,它出現(xiàn)在目前的版本中僅僅是為了兼容性的原因。這個(gè)接口的方法將模擬以前的版本的定義返回相應(yīng)的值。
                方法
                1、getSession
                public HttpSession getSession(String sessionId);
                當(dāng)初用來返回與這個(gè)session id相關(guān)的session。現(xiàn)在返回空值。
                2、getIds
                public Enumeration getIds();
                當(dāng)初用來返回這個(gè)環(huán)境下所有session id的列表。現(xiàn)在返回空的列表。

                六、Cookie類\
                定義\
                public class Cookie implements Cloneable
                這個(gè)類描述了一個(gè)cookie,有關(guān)cookie的定義你可以參照Netscape Communications Corporation的說明,也可以參照RFC 2109。
                構(gòu)造函數(shù)
                public Cookie(String name, String value);
                用一個(gè)name-value對定義一個(gè)cookie。這個(gè)name必須能被HTTP/1.1所接受。
                以字符$開頭的name被RFC 2109保留。
                給定的name如果不能被HTTP/1.1所接受,該方法拋出一個(gè)IllegalArgumentException。
                方法
                1、getComment
                public String getComment();
                返回描述這個(gè)cookie目的的說明,如果未定義這個(gè)說明,返回空值。
                2、getDomain
                public String getDomain();
                返回這個(gè)cookie可以出現(xiàn)的區(qū)域,如果未定義區(qū)域,返回空值。
                3、getMaxAge
                public int getMaxAge();
                這個(gè)方法返回這個(gè)cookie指定的最長存活時(shí)期。如果未定義這個(gè)最長存活時(shí)期,該方法返回-1。
                4、getName
                public String getName();
                該方法返回cookie名。
                5、getPath
                public String getPath();
                返回這個(gè)cookie有效的所有URL路徑的前綴,如果未定義,返回空值。
                6、getSecure
                public boolean getSecure();
                如果這個(gè)cookie只通過安全通道傳輸返回真,否則返回假。
                7、getValue
                public String getValue();
                該方法返回cookie的值。
                8、getVersion
                public int getVersion();
                返回cookie的版本。版本1由RFC 2109解釋。版本0由Netscape Communications Corporation的說明解釋。新構(gòu)造的cookie默認(rèn)使用版本0。
                9、setComment
                public void setComment(String purpose);
                如果一個(gè)用戶將這個(gè)cookie提交給另一個(gè)用戶,必須通過這個(gè)說明描述這個(gè)cookie的目的。版本0不支持這個(gè)屬性。
                10、setDomain
                public void setDomain(String pattern);
                這個(gè)方法設(shè)置cookie的有效域的屬性。這個(gè)屬性指定了cookie可以出現(xiàn)的區(qū)域。一個(gè)有效域以一個(gè)點(diǎn)開頭(.foo.com),這意味著在指定的域名解析系統(tǒng)的區(qū)域中(可能是www.foo.com但不是a.b.foo.com)的主機(jī)可以看到這個(gè)cookie。默認(rèn)情況是,cookie只能返回保存它的主機(jī)。
                11、setMaxAge
                public void setMaxAge(int expiry);
                這個(gè)方法設(shè)定這個(gè)cookie的最長存活時(shí)期。在該存活時(shí)期之后,cookie會(huì)被終目。負(fù)數(shù)表示這個(gè)cookie不會(huì)生效,0將從客戶端刪除這個(gè)cookie。
                   12、setPath
                public void setPath(String uri);
                這個(gè)方法設(shè)置cookie的路徑屬性。客戶端只能向以這個(gè)給定的路徑String開頭的路徑返回cookie。
                13、setSecure
                public void setSecure(boolean flag);
                指出這個(gè)cookie只能通過安全通道(例如HTTPS)發(fā)送。只有當(dāng)產(chǎn)生這個(gè)cookie的服務(wù)器使用安全協(xié)議發(fā)送這個(gè)cookie值時(shí)才能這樣設(shè)置。
                14、setValue
                public void setValue(String newValue);
                設(shè)置這個(gè)cookie的值,對于二進(jìn)制數(shù)據(jù)采用BASE64編碼。
                版本0不能使用空格、{}、()、=、,、“”、/、?、@、:以及;。
                15、setVersion
                public void setVersion(int v);
                設(shè)置cookie的版本號(hào)

                七、HttpServlet類\
                定義\
                public class HttpServlet extends GenericServlet implements 
                   Serializable
                這是一個(gè)抽象類,用來簡化HTTP Servlet寫作的過程。它是GenericServlet類的擴(kuò)充,提供了一個(gè)處理HTTP協(xié)議的框架。
                在這個(gè)類中的service方法支持例如GET、POST這樣的標(biāo)準(zhǔn)的HTTP方法。這一支持過程是通過分配他們到適當(dāng)?shù)姆椒ǎɡ鏳oGet、doPost)來實(shí)現(xiàn)的。
                方法
                1、doDelete
                protected void doDelete(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP DELETE操作。這個(gè)操作允許客戶端請求從服務(wù)器上刪除URL。這一操作可能有負(fù)面影響,對此用戶就負(fù)起責(zé)任。
                這一方法的默認(rèn)執(zhí)行結(jié)果是返回一個(gè)HTTP BAD_REQUEST錯(cuò)誤。當(dāng)你要處理DELETE請求時(shí),你必須重載這一方法。
                2、doGet
                protected void doGet(HttpServletRequest request, 
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP GET操作。這個(gè)操作允許客戶端簡單地從一個(gè)HTTP服務(wù)器“獲得”資源。對這個(gè)方法的重載將自動(dòng)地支持HEAD方法。
                GET操作應(yīng)該是安全而且沒有負(fù)面影響的。這個(gè)操作也應(yīng)該可以安全地重復(fù)。
                這一方法的默認(rèn)執(zhí)行結(jié)果是返回一個(gè)HTTP BAD_REQUEST錯(cuò)誤。
                3、doHead
                protected void doHead(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP HEAD操作。默認(rèn)的情況是,這個(gè)操作會(huì)按照一個(gè)無條件的GET方法來執(zhí)行,該操作不向客戶端返回任何數(shù)據(jù),而僅僅是返回包含內(nèi)容長度的頭信息。
                與GET操作一樣,這個(gè)操作應(yīng)該是安全而且沒有負(fù)面影響的。這個(gè)操作也應(yīng)該可以安全地重復(fù)。
                這個(gè)方法的默認(rèn)執(zhí)行結(jié)果是自動(dòng)處理HTTP HEAD操作,這個(gè)方法不需要被一個(gè)子類執(zhí)行。 
                4、doOptions
                protected void doOptions(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP OPTION操作。這個(gè)操作自動(dòng)地決定支持哪一種HTTP方法。例如,一個(gè)Servlet寫了一個(gè)HttpServlet的子類并重載了doGet方法,doOption會(huì)返回下面的頭:
                Allow: GET,HEAD,TRACE,OPTIONS
                你一般不需要重載這個(gè)方法。
                5、doPost
                protected void doPost(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP POST操作。這個(gè)操作包含請求體的數(shù)據(jù),Servlet應(yīng)該按照他行事。
                這個(gè)操作可能有負(fù)面影響。例如更新存儲(chǔ)的數(shù)據(jù)或在線購物。
                這一方法的默認(rèn)執(zhí)行結(jié)果是返回一個(gè)HTTP BAD_REQUEST錯(cuò)誤。當(dāng)你要處理POST操作時(shí),你必須在HttpServlet的子類中重載這一方法。
                6、doPut
                protected void doPut(HttpServletRequest request, 
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP PUT操作。這個(gè)操作類似于通過FTP發(fā)送文件。
                這個(gè)操作可能有負(fù)面影響。例如更新存儲(chǔ)的數(shù)據(jù)或在線購物。
                這一方法的默認(rèn)執(zhí)行結(jié)果是返回一個(gè)HTTP BAD_REQUEST錯(cuò)誤。當(dāng)你要處理PUT操作時(shí),你必須在HttpServlet的子類中重載這一方法。
                7、doTrace
                protected void doTrace(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                      IOException;
                被這個(gè)類的service方法調(diào)用,用來處理一個(gè)HTTP TRACE操作。這個(gè)操作的默認(rèn)執(zhí)行結(jié)果是產(chǎn)生一個(gè)響應(yīng),這個(gè)響應(yīng)包含一個(gè)反映trace請求中發(fā)送的所有頭域的信息。
                當(dāng)你開發(fā)Servlet時(shí),在多數(shù)情況下你需要重載這個(gè)方法。
                8、getLastModified
                protected long getLastModified(HttpServletRequest request);
                返回這個(gè)請求實(shí)體的最后修改時(shí)間。為了支持GET操作,你必須重載這一方法,以精確地反映最后修改的時(shí)間。這將有助于瀏覽器和代理服務(wù)器減少裝載服務(wù)器和網(wǎng)絡(luò)資源,從而更加有效地工作。返回的數(shù)值是自1970-1-1日(GMT)以來的毫秒數(shù)。 
          默認(rèn)的執(zhí)行結(jié)果是返回一個(gè)負(fù)數(shù),這標(biāo)志著最后修改時(shí)間未知,它也不能被一個(gè)有條件的GET操作使用。
                9、service
                protected void service(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                      IOException;
                public void service(ServletRequest request, ServletResponse response)
                      throws ServletException, IOException;
                這是一個(gè)Servlet的HTTP-specific方案,它分配請求到這個(gè)類的支持這個(gè)請求的其他方法。
                當(dāng)你開發(fā)Servlet時(shí),在多數(shù)情況下你不必重載這個(gè)方法。

                八、HttpSessionBindingEvent類\
                定義\
                public class HttpSessionBindingEvent extends EventObject
                這個(gè)事件是在監(jiān)聽到HttpSession發(fā)生綁定和取消綁定的情況時(shí)連通HttpSessionBindingListener的。這可能是一個(gè)session被終止或被認(rèn)定無效的結(jié)果。
                事件源是HttpSession.putValue或HttpSession.removeValue。
                構(gòu)造函數(shù)
                public HttpSessionBindingEvent(HttpSession session, String name);
                通過引起這個(gè)事件的Session和發(fā)生綁定或取消綁定的對象名構(gòu)造一個(gè)新的HttpSessionBindingEvent。
                方法
                1、getName
                public String getName();
                返回發(fā)生綁定和取消綁定的對象的名字。
                2、getSession
                public HttpSession getSession();
                返回發(fā)生綁定和取消綁定的session的名字。

                   九、HttpUtils類\
                定義\
                public class HttpUtils
                收集HTTP Servlet使用的靜態(tài)的有效的方法。
                方法
                1、getRequestURL
                public static StringBuffer getRequestURL(HttpServletRequest
                      request);
                在服務(wù)器上重建客戶端用來建立請求的URL。這個(gè)方法反映了不同的協(xié)議(例如http和https)和端口,但不包含查詢字符串。
                這個(gè)方法返回一個(gè)StringBuffer而不是一個(gè)String,這樣URL可以被Servlet開發(fā)者有效地修改。
                2、parsePostData
                public static Hashtable parsePostData(int len, 
                      ServletInputstream in);
                解析一個(gè)包含MIME類型application/x-www-form-urlencoded的數(shù)據(jù)的流,并創(chuàng)建一個(gè)具有關(guān)鍵值-數(shù)據(jù)對的hash table。這里的關(guān)鍵值是字符串,數(shù)據(jù)是該字符串所對應(yīng)的值的列表。一個(gè)關(guān)鍵值可以在POST的數(shù)據(jù)中出現(xiàn)一次或多次。這個(gè)關(guān)鍵值每出現(xiàn)一次,它的相應(yīng)的值就被加入到hash table中的字符串所對應(yīng)的值的列表中。
                從POST數(shù)據(jù)讀出的數(shù)據(jù)將經(jīng)過URL解碼,+將被轉(zhuǎn)換為空格以十六進(jìn)制傳送的數(shù)據(jù)(例如%xx)將被轉(zhuǎn)換成字符。
                當(dāng)POST數(shù)據(jù)無效時(shí),該方法拋出一個(gè)IllegalArgumentException。
                3、parseQueryString
                public static Hashtable parseQueryString(String s);
                解析一個(gè)查詢字符串,并創(chuàng)建一個(gè)具有關(guān)鍵值-數(shù)據(jù)對的hash table。這里的數(shù)據(jù)是該字符串所對應(yīng)的值的列表。一個(gè)關(guān)鍵值可以出現(xiàn)一次或多次。這個(gè)關(guān)鍵值每出現(xiàn)一次,它的相應(yīng)的值就被加入到hash table中的字符串所對應(yīng)的值的列表中。
                從查詢字符串讀出的數(shù)據(jù)將經(jīng)過URL解碼,+將被轉(zhuǎn)換為空格以十六進(jìn)制傳送的數(shù)據(jù)(例如%xx)將被轉(zhuǎn)換成字符。
                當(dāng)查詢字符串無效時(shí),該方法拋出一個(gè)IllegalArgumentException。
          posted @ 2007-07-26 16:34 edsonjava 閱讀(458) | 評論 (0)編輯 收藏
           

          CVSNT 2.5.03 Installation on Windows 2003

          Author: Bo Berglund
          Notice:
          This guide is written as an installation help for CVSNT 2.5.03 and higher on Windows 2003 server.
          Most of the discussion is also valid for installation on Windows XP-Pro (see below for an important setting).
          NOTE! You cannot use XP-Home for CVSNT!
          The guide uses the Innosetup based installer that I maintain but similar results can probably be obtained by using the Innosetup installer published by Oliver Giesen as well.
          I am not using the MSI installer from the official CVSNT website since I cannot accept non-opensource software if anything else is available.

          Table of contents
          CVSNT Installation
          Configuring the server
          Adding CVS users
          Adding CVS administrators
          Disabling pserver as security measure
          The cvs passwd command for adding users
          Managing pserver and sserver users
          Using the SSPI protocol
          Fine-tuning user access of CVS
          Using spaces with CVSNT

          Links:
          CVSNT Auditing Configuration Tutorial
          Innosetup CVSNT Installer download
          CVSMailer homepage, Automatic email on commits and other events
          ViewCvs Installer download
          CVSNT command reference
          CVSNT download (where you can download the latest CVSNT versions)

          Karl Fogel's book 'Open Source development with CVS'
          The free part of Karl Fogel's book in HTML format
          DevGuy's CVS information pages
          CVS-Gui (WinCvs) homepage
          WinCvs Dialy use guide
          WinCvs 1.3 manual (PDF format)

          WinCvs download (on SourceForge)

          Installation of the CVSNT server

          File system type
          Make sure your system is only using the NTFS file system!
          Also make sure you are logged on as an administrator of the PC (using an account with administrative priviliges).
          And most important: Use the local disk on the CVSNT server!

          IMPORTANT for XP-Pro users:
          You MUST switch off Simple File Sharing, which is the default for XP (as recommended by Microsoft to make XP somewhat compatible with Win95-98-ME)!
          You do this by opening a Windows Explorer and then use the menu command Tools/Folder Options. Select the View tab and scroll down to the bottom where you find this item. Uncheck it now!
          Simple File Sharing

          Now for the actual installation and configuration:

          1. Get the latest release of CVSNT
          Get the latest CVSNT Innosetup installation from Innosetup CVSNT Installer download

          2. Create CVS directories
          Create two directories on the target machine, c:\cvsrepos and c:\cvsrepos\cvstemp. If you have a separate disk partition to spare for CVS then use that instead. The important point here is that the disk where the repository is located on is NTFS.

          3. Directory security and permissions
          Give c:\cvsrepos\cvstemp security settings that allows full control for all accounts including SYSTEM.
          Important:
          The cvstemp directory must NOT be located in either c:\WINNT\Temp or anywhere in the "C:\Documents and Settings" tree because these locations have imposed restrictions on user access!
          Notice that on XP-Pro out of the box from Microsoft the permissions cannot be set like this until "Simple File Sharing" is switched off (see above). So you must do this if you use XP-Pro. XP-Home is totally unsuitable for CVSNT!

          4. Install CVSNT
          Run the downloaded CVSNT setup file and make sure to change the installation path to c:\programs\cvsnt (I am paranoid about removing any spaces in paths used by cvs!)
          Start screen:
          Install screen #1

          License agreement:
          Install screen #2

          Install directory selection:
          Note:
          I strongly recommend that you install CVSNT to a path that does NOT contain any embedded spaces, for example like this:
          Install screen #3

          Installation component selection screen:
          Install screen #4

          Start menu selection:
          Install screen #5

          Task selection screen:
          Install screen #6

          Ready to install!
          Install screen #7

          Install in progress
          Install screen #8

          Release notes
          Install screen #9

          Installation done!
          Install screen #10


          Configuring the CVSNT server and repository


          1. CVSNT Control Panel configuration
          CVSNT is configured from the CVSNT Control Panel, which can be reached via the shortcut link placed under the Start menu during installation.
          Control Panel

          Now open the CVSNT control panel applet and do the following:

          2. Shut down the CVSNT service
          Check that the CVSNT Service is not running (Start button is enabled). This is the initial screen showing that both services are running:

          Configuration screen #1
          If it is started then stop it. You can leave the Lock Service running.

          3. Repository creation
          The tab will initially look like this:

          Configuration screen #2

          4. Add repository
          Now you will add a repository to the server. This is done using the "Add" button. When you click this a dialogue shows up where you will define your repository.

          Empty repo

          5. Repository folder
          Click the ellipsis button for Location to bring up the folder browser.
          Now you can browse to the location you want for your repository and add a new folder here.
          NOTE:
          I strongly advice NOT to use paths with embedded spaces for CVS!

          Browse for folder

          6. Name repository
          Now fill in the description and the name of the repository as well.
          NOTE:
          Do NOT
          accept the suggested name, which is the same as the folder path!
          Instead only use the bare folder name with a leading / like this:

          CVSNT AddRepository

          7. Initializing the repository
          When you click the OK button there will be a dialog where CVSNT offers to initialize the new repository.
          When you click Yes then the new folder will be converted to a real repository:

          CVSNT AddRepository


          8. First repository added!
          Now the list of repositories has been populated with the first repository:

          CVSNT Repository


          You can add as many as you like (almost) but please do not fall for the temptation to use one repository for each and every project! There are a lot of possibilities to streamline the development process using CVSNT, but many of these use the virtual modules concept and this is only possible within a single repository.


          9. Server Settings
          Now go on to the Server Settings tab.
          Here the default settings are all right for now, except the Temporary Directory setting.

          Serversettings

          NOTICE about Domains:
          You can set the Default domain entry to either the CVSNT server PC name (as in the example above) or the domain name to which the CVSNT server belongs. CVSNT will strip the domain part from all accounts that log on using the default domain before processing. All other logons will be processed using their complete names (DOMAIN\username). The result of this is that all users that "belong" to the domain specified in this box will be logged using only the account name, likewise these usernames will be supplied to the administrative scripts without the domain name. All others will have a domain name added. This must be accounted for in any admin script used.
          The CVSROOT/users file is one such admin file that needs to be handled with care concerning domain and non-domain entries.

          Temp dir: Use the ellipsis button to browse for the folder prepared for this purpose above:

          Tempdir

          10. Compatibility
          On the next tab (Compatibility Options) there is nothing you need to change for now:

          Serversettings screen #1


          11. Plugins and protocols
          The Plugins tab define a lot of the extra features of CVSNT including some aspects of the connection protocols. The sceen list the available plugins and when you select a line you will be able to configure this plugin by clicking the configure button:

          Serversettings screen #1


          12. Sserver configuration
          Here is the configuration window for the SSERVER protocol plugin. Please set it like this:

          SSPI config screen


          13. Advanced settings
          The final tab on the Control Panel deals with advanced configuration settings and you need not change anything here.

          Configuration screen #1


          14. Apply configuration changes
          Now click the Apply button! This is really important, nothing will happen unless you do this! Note that after you have done this the Apply button is disabled.

          15. Start the CVSNT service
          Go back to the first tab and click the Start button. After a few moments the Stop button will be highlighted.
          Now CVSNT runs (success!)

          16. Restart the server
          In order for you to be able to use the command line cvs you need to have the path variable set to include the location of the cvs.exe just installed (c:\programs\cvsnt). Since the installer will have put this into the system path variable it will work if you restart the server.
          You can check this by going to a command window and typing the command:
          cvs --ver
          If this results in an eror message then you should restart the server PC before continuing.

          Adding and managing CVS users for pserver and sserver access

          This is a step that is only needed if you plan on using the sserver or pserver protocols with this CVS server. If your users are all on Windows PC:s pserver is not recommended since it has inherent security flaws. Instead use SSPI because that protocols integrate much better with Windows. If you decide to go with sspi (recommended) then you can skip the discussion on how to add and manage users in this section.

          1. Creating CVS accounts on the server
          In order for pserver and sserver to work you have to define CVS users, but before you can do this you need to create two real accounts on the server. These accounts will be used by the CVS users as the working accounts.
          You need one account which will be a CVS administrative account and one which will be a normal user account. Note that the CVS administrator need not be a server administrator!

          Usermanager

          The two accounts are added through the Users dialog in Computer Management.
          I have used the account names cvsadmin and cvsuser as shown above.

          2. Adding CVS users
          Open a command window and do the following (replace items <text> with the real values from your system).

          set cvsroot=:sspi:<computername>:/TEST
          cvs passwd -a <account name>

          You will now be asked to enter a password for this user. This password is only for CVS use so it should not be the real system password! Enter the password twice.
          Now the CVSROOT/passwd file will be created and the user you entered will be added to the list in this file.
          This step is necessary if you are going to use the pserver or sserver protocol in the future since there is no way to log in with pserver/sserver unless there is a passwd file present with the user listed.

          Important note:
          Any user entered like this MUST be an NT user on the local system! CVS will not accept any user login that is not connected to a "real" account.

          3. Aliasing CVS users to real accounts
          In order to have many CVS user logins you don't need to create masses of system accounts! Instead you can "alias" a CVS login to a "real" account using this command:

          cvs passwd -r <real accountname> -a <cvs login name>

          What will happen now is that to CVS the user will be known and registered as the CVS login given in the command, but for file operations that will encounter permission issues the commands will be executed in the context of the real system account that was aliased. This makes it possible to use NTFS file system permissions to limit access to certain parts of the repository to some users. You simply create a system account for which you set limited permissions and then you alias the CVS login to this user.

          Note that this command will fail if there is a space embedded in the real account name! DON'T ever use spaces in these contexts!!!!! (But using quotes may solve the problem like this:
          cvs passwd -r "system admin" -a "new user"
          Since I don't have a valid user with embedded space I could not check the quotes trick with the valid user name parameter, but adding a CVS login with space embedded *can* be done with quotes.)

          Examples:
          cvs passwd -r cvsuser -a charlie

          or if you want the new user to be a CVS administrator:

          cvs passwd -r cvsadmin -a rogerh

          Note about Domain users:
          You can add domain users with the following command:
          cvs passwd -r <real accountname> -D <domain name> -a <cvs login name>
          This command is reported by a user to have worked for him. I cannot check it because I don't have a domain. But based on information from the mail list I think that it will only work if there is a trust between the CVSNT server PC and the domain controller. If the CVSNT server PC is a member of the domain then this is the case.

          The server is now ready to be used and you can check the pserver functionality by doing this:

          4. Testing the CVS connection with sserver
          Open another command window and type:
          set cvsroot=:sserver:<user>@<computername>:/TEST
          Replace <user> and <computername> with valid entries like:
          set cvsroot=:sserver:charlie@cvsserver:/TEST

          Then:
          cvs login (enter password on prompt)
          cvs ls -l -R
          (this should give you a list of the files in TEST/CVSROOT)

          5. Testing the CVS connection with pserver
          Open another command window and type:
          set cvsroot=:pserver:<user>@<computername>:/TEST
          Replace <user> and <computername> with valid entries like:
          set cvsroot=:pserver:charlie@cvsserver:/TEST

          Then:
          cvs login (enter password on prompt)
          cvs ls -l -R
          (this should give you a list of the files in TEST/CVSROOT)

          6. Testing the CVS connection from another PC
          Open a command window on another PC where you have installed the CVSNT in client only mode and type:
          set cvsroot=:sserver:<user>@<computername>:/TEST
          Replace <user> and <computername> with valid entries like:
          set cvsroot=:pserver:charlie@cvsserver:/TEST

          Then:
          cvs login (enter password on prompt)
          cvs ls -l -R
          (this should give you a list of the files in TEST/CVSROOT)

          If you cannot get this far, for example if the login fails, then you should check the Windows Firewall settings on the CVSNT server:

          7. Modifying Windows Firewall to allow CVS calls

          • Go to Control Panel
          • Open the Windows Firewall item.
          • Select the Exceptions tab
          • Click the "Add port" button
          • Enter the name CVSNT and port number 2401 as a TCP port
          • Accept back to the main screen
          • Make sure Windows Firewall is set to ON

          Configuration screen #1

          Configuration screen #1

          Configuration screen #1

           

          Administrating the repository, users with admin rights

          There have been a number of reports that people have not been able to add users or execute the cvs admin command even though they were members of the Administartors group or even of Domain Admins. In order to avoid this there is a simple way to manage who will have admin rights on the CVSNT server. It is done through the CVSROOT/admin file.
          Here is how to:

          • Create a text file called admin (no extension) inside the CVSROOT directory of the repository.
          • Edit this file by adding on separate lines the login names of the users you want to give administrative priviliges on the CVS server.
          The file could look like this:
          cvsadmin
          charlie
          jennifer
          john

          Now each of these users are able to add new users, change their passwords and use the cvs admin command.

           

          Disabling the pserver protocol

          If you are exposing your CVSNT server to the Internet you should disable the :pserver: protocol because it uses too low security levels. Only the password for login is 'encrypted' and this is only barely so. All other traffic is in cleartext...
          To protect your data you should use the :sspi: protocol instead (and set its encryption flag of course).
          As an alternative with the same basic functionality as pserver you can use sserver instead. This uses encrypted connections by default and is probably better if you want to add cvs logins that do not correspond to real accounts (see above).
          Disabling any protocol on the CVSNT server is done through the CVSNT Control Panel Plugins tab.
          Select the :pserver: protocol line and click Configure. This will bring up a dialogue where you can just uncheck the checkbox to disable the protocol:

          Configuration screen #1


          Adding new pserver users using the cvs passwd command

          As soon as you have logged on using pserver or sserver with a cvs login name that is the same as a local system admin or is aliased to an admin account or is listed in the CVSROOT/admin file then you can add and delete CVS user logins with the passwd command. Here is the full syntax for this command:

          Usage:
          cvs passwd [-a] [-x] [-X] [-r real_user] [-R] [-D domain] [username]
          -a Add user
          -x Disable user
          -X Delete user
          -r Alias username to real system user
          -R Remove alias to real system user
          -D Use domain password

          Example:
          cvs passwd -r charlie -a john
          This adds a CVS login john with a system alias to account charlie. When the command is executed there will be a password dialogue that asks for the password of john twice for confirmation. Note that this is NOT the actual system password of account john, it is the CVS login password only used by CVSNT.
          After the command completes there will be a new line in the CVSROOT/passwd file looking somewhat like this:
          john:KacIT8t1F/SKU:charlie
          The part between the :: is the DES encrypted password you typed in and will be used by the CVSNT service during login to validate john. Once accepted the account charlie will instead be used so the password is no longer used. The CVSNT service has full priviliges to act on charlie's behalf and this is what it does too.

          Managing pserver and sserver users

          If you plan on using pserver or sserver with a fairly large number of different user logins then you might want to do as follows (also described above):

          • Create a local user on the CVSNT server by the name of "cvsuser".
          • Login to the cvs server using an admin account.
          • Add the logins with the following command to alias to the cvsuser:
            cvs passwd -r cvsuser -a <login user name>
            You will be asked twice for the login password.
          You may add as many pserver users this way as you like. They will all be individually identified by the login name even though the operations on the repository will be done in the cvsuser account context. Mail systems will recognize these user names as well (see below).

           

          Using the SSPI protocol for CVSNT access

          A few years ago the SSPI protocol was added to CVSNT. It works over TCP/IP so it can more easily traverse firewalls. Like :ntserver:, which is now depreciated, the :sspi: protocol does not need a login, instead the login you did when you started your workstation is used with this protocol.

          Limiting user access with sspi
          When used normally sspi will accept connections from all system users that authenticate against the system (local or domain). Often this is not really what we want, instead we want to use the same mechansism as is used with :pserver:. Here the CVSROOT/passwd file limits the logins accepted by CVSNT to those mentioned in the file.
          With :sspi: this is quite possible, you only have to list the account login names that you want to give CVS access in the passwd file. You also have to set the parameter
          SystemAuth = No
          in the CVSROOT/config file.
          Note that in this case there is no need for entering passwords into the passwd file, sspi uses the system login and the passwd file is only used as a list of accepted users. So simply issuing this command when logged in as a CVS administrator will work:
          cvs passwd -a newuser
          (press enter twice to tell CVSNT that no password is used)

          Fine-tuning user access of CVS

          The NTFS file system permissions can be used to tune the access to the CVS repository with more granularity than the passwd file allows. Here is how it is done:

          1. Create a number of NT user groups where members can be added and removed easily.
          2. Don't use aliases in the login scheme, let each user login as himself, for example using :sspi:.
          3. Set permissions (read/write, read only, no access) on the module level in the repository using the CVS groups as tokens.
          4. Give membership to the CVS user groups as needed to individual NT accounts

           

          Using spaces with CVSNT

          CVSNT tries its best to handle spaces embedded in file and directory names. But there still are instances where the use of spaces breaks the CVS functionality badly. So my recommendations are:

          1. Install CVSNT to a path that does not contain spaces.
          2. Place the repository on a path not containing spaces.
          3. If you install additional software like PERL or RCS, don't use spaces!
          4. Instruct your users not to use spaces in directory names that are to be handled by CVS.

          People may argue that CVSNT handles these issues for them, but in my experience this is only partly true. For example the loginfo and notify script parsing breaks fully when handling files with embedded spaces. There are other places as well...
          Also by allowing spaces you will make it impossible to later move the repository to a *nix system (Unix, Linux etc).
          So you are much better off prohibiting spaces up front!

          Afterwords

          This tutorial is written 2005-11-16 and is based on CVSNT version 2.5.03.2148.
          The test system is Windows Enterprise Server 2003 with SP1 installed running in Virtual PC 2004 SP1 on my development PC. The server is not member of a domain.

          Comments? Send me a message: Bo Berglund

          posted @ 2007-07-16 14:22 edsonjava 閱讀(2344) | 評論 (0)編輯 收藏
           
          主站蜘蛛池模板: 封开县| 莱州市| 南溪县| 太谷县| 会同县| 湄潭县| 辽宁省| 白玉县| 赤城县| 吉林省| 青岛市| 泰和县| 大埔县| 鄱阳县| 嘉兴市| 万年县| 平阳县| 同心县| 天峨县| 谷城县| 滦平县| 若尔盖县| 光山县| 青龙| 黄冈市| 原平市| 忻城县| 额敏县| 泗洪县| 荆州市| 工布江达县| 双峰县| 右玉县| 太湖县| 河南省| 九龙县| 旬邑县| 合水县| 花莲市| 聂拉木县| 南皮县|