<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-13650940</id><updated>2011-12-29T15:55:25.245-08:00</updated><title type='text'>JAVA,JSP,XML 技術專欄</title><subtitle type='html'>本欄是繁體的JAVAXML專欄，並在&lt;a href="http://javaxml.blog-city.com"&gt;BLOGCITY&lt;/a&gt;有影像站點。本欄主要記錄JAVA、XML方向的技術體驗，經驗總結的原創類文章，及精華性摘錄</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-13650940.post-112861467413229916</id><published>2005-10-06T09:03:00.000-07:00</published><updated>2005-10-06T09:04:34.140-07:00</updated><title type='text'>什?情況下應該把網站的頁面變成靜態網頁發布？</title><content type='html'>WEB界面靜態化進入最後的環節，可以令管理員分門分類分子網地選擇項目進行靜態化，主要是首頁，效率很高，按由XML設定的靜態化項目，一 個網站管理員可以在幾分鍾內完成上千個首頁的靜態化發布。但是當進入到再翻頁部分時，卻令我沈思了整整半天，覺得前面幾天的路,也許走錯了。&lt;br /&gt;&lt;br /&gt;要知道錯在什?地方，最好先看看?什?要進行WEB界面靜態化。我絕不在乎已經浮了兩年多的所謂不能把WEB界面變成靜態頁面就是技術不佳的話，事實上， 今天才開始靜態化是由于搜索引擎的要求。換言之，如果不是由于有搜索引擎極大的訪問壓力，僅僅是人的點擊的話，根本不需要考慮動態網頁靜態提供。這就是路 可能走錯的原因，因?，對于人來說，把首頁進行靜態化是可以減輕訪問壓力的；而對于搜索引擎來說，如果梢頁也是以?靜態形式提供的話，那?是否首頁並不重 要了，因?搜索引擎會順著連接把整個網站搜個遍，如果僅僅是把首頁靜態化，對于減輕搜索引擎的壓力沒有什?幫助，如果是把所有異化的網頁全部靜態化，工程 何其大也，包括使用者網站編輯，她們能夠承受嗎？&lt;br /&gt;&lt;br /&gt;把首頁靜態化的原因，說起來主要與中國國內的網站設計陋習有關：總是把首頁做得奇大無比，塞滿了沒有人看的垃圾。因此，假設受?總是先到首頁的話，那?首 頁的負載就是後續頁面的幾十倍，把它靜態化，也就省下了資源。但實際上目前的趨勢，或者說國外網站的大勢是使用精簡的小首頁，這樣靜態化就沒有太大的必 要；如果訪問負載來自于搜索引擎的話，就更沒有必要了。&lt;br /&gt;&lt;br /&gt;那?什?內容應該以靜態網頁提供呢？大致可以把網頁分成三類：一是導航性網頁，這類頁面變化少，適宜使用靜態頁面提供；國外網站的首頁一般是這種形式；二 是內容分類列表、摘要網頁，這類是相對于書本的目錄，如果是更新頻繁的話，靜態網頁很難做，主要是需要實時更新的內容太多，一般適宜動態網頁；三是內容 頁，如文章內容，這類網頁罕有訪問，也極少變動，適于變成靜態網頁。國內的網站的常見的大首頁，主要是把第一類和第二類的功能混淆起來。我的系統的功能目 前是主要把第一類變成靜態，還是挺有用的，但嘗試把第二類變成靜態，就不恰當了，這就是我錯的地方。&lt;br /&gt;&lt;br /&gt;“把動態頁面轉成靜態頁面”，需求看似簡單，但只有實際做下去，才知道什?是合適的，什?不是合適的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-112861467413229916?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/112861467413229916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=112861467413229916' title='368 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112861467413229916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112861467413229916'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/10/blog-post.html' title='什?情況下應該把網站的頁面變成靜態網頁發布？'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>368</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-112761521899814038</id><published>2005-09-24T19:16:00.000-07:00</published><updated>2005-09-24T19:26:59.010-07:00</updated><title type='text'>使用DBCopier進行不同數據庫間的數據移植</title><content type='html'>DBCopier同樣是在多數據庫環境中，?了適應數據整理和拷貝而開發的可重用構件。不過，實際上，更多的情況是用在不同的開發過程中由于表結構的修改，而需要對曆史數據進行整理歸一的過程。&lt;br /&gt;&lt;br /&gt;DBCopier的工作核心是mission.xml，每一個mission是一個拷貝任務；不同的數據庫連接在connectionset元素中定義，實際上，這與ConnextionManger和DAO中的定義和解釋是一樣的。&lt;br /&gt;如：&lt;br /&gt;&lt;connection-set&gt;&lt;br /&gt;    &lt;connection name="mysql" driver="com.mysql.jdbc.Driver" username="conn" password="abcd"&gt;&lt;br /&gt;        &lt;uri&gt;&lt;![CDATA[jdbc:mysql://127.0.0.1:3306/daifumd?useUnicode=true&amp;characterEncoding=gb2312]]&gt;&lt;/uri&gt;&lt;br /&gt;    &lt;/connection&gt;   &lt;br /&gt;    &lt;connection name="conn" driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;        uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="conn" password="&lt;br /&gt;abcd" /&gt;&lt;br /&gt;    &lt;connection name="reso" driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;        uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="reso" password="abcd" /&gt;&lt;br /&gt;    &lt;connection name="daifu" driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;        uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="daifu" password="abcdef" /&gt;&lt;br /&gt;    &lt;connection name="system" driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;        uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="system" password="abcdefg" /&gt;&lt;br /&gt;&lt;/connection-set&gt;&lt;br /&gt;&lt;br /&gt;定義了若幹個數據庫連接定義。根據需要，DBCopier可以把不同的數據庫中的表拷貝到另一個數庫的某個或幾個表上，也可以在同一個數據庫中拷貝。&lt;br /&gt;&lt;br /&gt;每一個mission是一個任務：&lt;br /&gt;&lt;mission name="sectart" target="mysql" source="mysql.simplebase" condition="type=7" range="*" step="100" index="id" logging="false"&gt;&lt;br /&gt;    &lt;query name="read"&gt;&lt;br /&gt;        &lt;sql&gt;&lt;![CDATA[select * from simplebase WHERE id &gt;= ${MIN} and id &lt; ${MAX}]]&gt;&lt;/sql&gt;&lt;br /&gt;    &lt;/query&gt;&lt;br /&gt;    &lt;query name="write"&gt;&lt;br /&gt;&lt;sql&gt;insert into sectart (name,chn,deleted,on_off_line,section,type,remark) values (${name},${chn},${deleted},${on_off_line},${section},${type},${remark})&lt;/sql&gt;&lt;br /&gt;    &lt;/query&gt;&lt;br /&gt;&lt;field name="type" sname="parentid" ttype="int"&gt;&lt;br /&gt;&lt;field name="deleted" ttype="int"&gt;&lt;br /&gt;&lt;field name="on_off_line" ttype="int"&gt;&lt;br /&gt;&lt;/mission&gt;&lt;br /&gt;&lt;br /&gt;詳細定義是：&lt;br /&gt;mission代表一?拷?任?；&lt;br /&gt;mission.(target/source) 分?表明拷?的目?和?源，?构是(?据源.表名),意?是直接??表操作，?管主要由Query????，或者是Clazz，但是在?算步?和?量?仍需要?里的表名。反而是target可以直接?据源名?。&lt;br /&gt;mission.index 指示是以什么域作?拷???的指?，如id;&lt;br /&gt;mission.range;采用1-2000??的形式，前者是起始，后是??（?照index）；如果是“*”，表示全部拷?（默?）。&lt;br /&gt;mission.step:步?，即每次?作?程拷?多少，??相?于?置??大小；每次?行step的?目，或????（小于step?）&lt;br /&gt;mission.condition是拷??象的附加?件；可以直接?作cdata形式;&lt;br /&gt;mission.query元素： 每?mission目前可以定?多?Query?象，但至少包括分?命名?write的Query?象，如果?有mission.clazz作??入源， ?必?有一?名?read的Query?象;特?注意read?象，如果其中有"WHERE"一定要大?，特?是在condition有?西的?侯；$ {MIN}/${MAX}是程序?定的大值和小值??，与range配合，即使是“*”，???值也是必?的；因?步???的?侯需要???值&lt;br /&gt;注意：query.sql中如果有域是long/clob型的，一定要?在最前面，否?可能出?；&lt;br /&gt;&lt;br /&gt;mission.clazz元素：{&lt;br /&gt;    ?于一些复??构的?据?象?型，很?确定?一?表?表的抄?，同?也?包含有多?的互相?束，??侯需要使用?据?象作??据源；即每一??象?例是相 ?于一行主表的??，它的?性是各?基表或子表值；clazz?象tools.xmlobj.Clazz必???tools.COPIER接口，并用?准 的setter/getter取/置值；&lt;br /&gt;    clazz.attribute?象；主要包括三??性，name,value,和type,type用于反射?的class型?得，因此要求完全的名?，以便在程序中Class.forName();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;mission.field；{&lt;br /&gt;DBCopier??上是使用Query.write中的?量?得一?串，然后通???串?索qread或者是cread形成一?名值?填充好一?完整的 sql,最后?行??batchsql完成移植的目的。每??量串中的域?得值的方式各不相同，特?是在?多情?下?移的?程本身就是?原?不合理的?据 ??方式的重整，（?范化或非?范化），filed就是????需求?行?置。如果?有相?的field?置，?采用默??置，即名?相同且都是字符串 值；field的??是首先采?value值，然后按query取值，最后按常?取值；&lt;br /&gt;&lt;br /&gt;field.name:?名??与qwrite中的?量名?之一匹配；否?DBCopier?加以忽略；&lt;br /&gt;field.sname:?名?指老表中的域名?，DBCopier通????cread或qread的rs中??据；默?地与field.name相同；&lt;br /&gt;field.stype:?入的?型，???于使用qread特?重要，尤其?于date?型；&lt;br /&gt;field.ttype:?出的?型，是指插入的?型，主要是因?生成sql?字符串需要使用‘’括起?；&lt;br /&gt;filed.value:   value是?定的值；可用此直接?一行?值；如果是“system.time”，意思是取System.currentTimeMillis()的值；&lt;br /&gt;field.query:{&lt;br /&gt;    如果?域必???特?的查?得到值，就?定所用的query名?，??query??已?定?在同一?mission中。&lt;br /&gt;    field.query??上??了???程，一是以前述的方法?得一?指定的?量；代入query的sql?定，?行??sql再?取它的值；&lt;br /&gt;    ??field的域含?有重大的修改：&lt;br /&gt;    field.sname指代入field.query.sql中的?量名?，一定要与相?的?据?接中的表.域名?相同；&lt;br /&gt;    field.stype指???query?果?的?型；其余意思一?。&lt;br /&gt;    field.filter; 如果??域在存入新?中?需要??更替其中的一些字符串，?置好filter后用?????用。&lt;br /&gt;        }&lt;br /&gt;    注意:query的connetion查?到底是那一?的，常常是??的?系；&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;mission.filter，用于????程中的字符串列?行必要的字符替?和??；由field?用；&lt;br /&gt;&lt;br /&gt;在定義好後，執行:&lt;br /&gt;java DBCopier mission=xxxx;;&lt;br /&gt;程序就會按照步長一段一段地完成數據移植任務，不滿意就重新來一遍。之所以要分割步長，是為了避免多個連接游標在大數據表時溢出出錯。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-112761521899814038?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/112761521899814038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=112761521899814038' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112761521899814038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112761521899814038'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/09/dbcopier.html' title='使用DBCopier進行不同數據庫間的數據移植'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-112737334289820993</id><published>2005-09-21T20:35:00.000-07:00</published><updated>2005-09-22T00:15:45.123-07:00</updated><title type='text'>簡化多表連接的訪問方式，hanva中的database.service基表映射框架</title><content type='html'>在Hanva的框架中，多表連接的查詢，一般由以下的方式完成：&lt;br /&gt;1、對於條件限制上的連接，可以直接採用entity讀取，條件上的多表，僅限於條件上的擴充，與一般的單表查詢沒有什麼不同；可以設定list,也可以在entities標簽中直接設定連接條件；&lt;br /&gt;2、對於選定域也是多表的，如果沒有相應的類可選，原則上是依靠database.service把基表的連預先設出來，從而把多表的連接轉化為單表上的連接，簡化了連接操作；&lt;br /&gt;3、其他情況，不反對越過應用層直接使用SQL查詢（還沒有碰到過）；&lt;br /&gt;&lt;br /&gt;database.service基表轉化系統，在適應原來多表的環境中，是非常關鍵的一個部件，經過近一年的運轉，表明當初的設想是正確的，基本符合應用要求。database.service最早的設想是基於以下幾點：&lt;br /&gt;1、多表連接中最常見的情形是少記錄量的基表和多記錄量的主表的連接；&lt;br /&gt;2、基表的記錄量都比較地少；&lt;br /&gt;3、基表在一個數據庫方案中總是佔了總數的一半以上，對於基表的管理的開發，總是佔用了系統總開發時數的十分一以上，而重復性總是很高，而界面的使用率也是最低的。&lt;br /&gt;4、把數據庫的關系分割成單一的ER後，總是能夠體現出最重要的是主entity的管理，其他部分是極少動作的，包括基表和二級三級子表。&lt;br /&gt;&lt;br /&gt;database.service是針對上面幾點的解決方案，主要包括：&lt;br /&gt;1、使用XML放置簡短的基表記錄而不是使用數據庫方案，這樣，就省去了其餘基表的管理部分，使用寫字板就可以完成通常是一次性的管理；&lt;br /&gt;2、基表記錄的訪問量很大，而多表連接意味著多表遍歷，消耗的資源遠遠超過普通的單表連接，因此，把基表記錄放進內存而把多表連接簡化為單表，不但可以簡化應用服務器的工作，也能夠大幅度提高運行效率；&lt;br /&gt;3、對於不便於使用XML文本記錄的類型，支持使用數據庫記錄，然後在有訪問時就把這個基列讀出來，象一般的基表類型一樣工作；如果超過一段時間沒有訪問，就把這個基列清除出內存，騰出空間給即時的其他服務；&lt;br /&gt;4、基表，特別是特殊的基表工作，總是意味著獨立的可抽象的方法，分散到各個模板訪問中實現，會加大各個模板的工作量，把它抽象出來集中到基類服務模塊，可以省卻這部分的工作（可重復調用）。&lt;br /&gt;5、基表系統不考慮子表集合，那是XML/OR構想中解決的課題。&lt;br /&gt;&lt;br /&gt;database.service包括以下類組件：&lt;br /&gt;一、MemoryBase:&lt;br /&gt;顧名思義，就是單純存放在內存中的Base類，實際上在啟動、訪問前是存放在xml文件中，由XML結構保存的等同於原數據庫小基表的內容。在XML使用 方式還不熟練的時侯，是所有的基類放在一個大文件中，以減少初始化解釋的成本；目前，已經發現把不同的基表分散到小的文件中，在訪問時再解釋，可以減少對 內存資源的消耗，同時，解釋小文件的單次訪問的成本也在可接受範圍內，這樣的結構比老一版要好。&lt;br /&gt;&lt;br /&gt;二、SimpleBase；&lt;br /&gt;使用單一數據庫表存儲的的基表，這是針對某些基類記錄還是比較多的，超出十個以上如果手工在XML中管理會比較麻煩，而套用XContainer的自管理索引的升級也沒有做，這時侯，使用simplebase可以把主要的基列放在數據庫。&lt;br /&gt;&lt;br /&gt;三、multibase;;&lt;br /&gt;這是針對多對多的表關系結構及其主要訪問管理方法抽象出來的表類型；&lt;br /&gt;&lt;br /&gt;四、treebase/multitree&lt;br /&gt;treebase作為一個依靠parentid的反向遍歷，經反復對模式在實際項目中驗證，表明它的運行和應用效率都比較低，樹結構最合適的做法不是使用 parentid，而是使用listable的鏈表集合，以避開每次訪問的反向parentid的上溯遍歷算法。這條，已經由XML、XOR方式得到解 決，因此，在database.service中這兩項實際上已經被廢棄。（但在開發時它花的時間是最多的）。&lt;br /&gt;&lt;br /&gt;結語：&lt;br /&gt;無論是hanva和它的基表服務，以及hanva的前身使用視圖和子查詢來簡化J2EE中的多表查詢的復雜性和困難，其動機都是通過在數據庫或應用層上的 附加工夫，把應用層中的繁複而困難的對關系結構的映射簡化成單表結構。它盡管對數據庫的ER設計，盡可能地減少多表連接有範式上的指示作用，但並不是對關 系數據庫中的外鍵關系的否定，而只是對這種外鍵訪問的傳統的多表SQL鏈接的否定。對於兩層的應用，它沒有任何意義，對於三層的面向對象的應用系統，它很 可能是關系結構向關系對象結構轉化過程中的嘗試，盡管還沒有任何跡象表明它會是一個成功地廣泛得到應用的嘗試。&lt;br /&gt;&lt;br /&gt;附：&lt;br /&gt;    database是??使用一?Database.getInstance().getBase()的方法，提供?一的??base的方法；&lt;br /&gt;    database最基本的??是dao.Record,一?MemoryBase和一?SimpleBase??都是一?Record; MemoryBase?承Record的所有方法；同?SimpleBase?承了MemoryBase,其他的Base都?承自SimpleBase。 dao.Record作?所有base的父?，本身?承自vEntity-&gt;dao;并使用其中的方法。&lt;br /&gt;    ??是memorybase，simplebase,multibase都是返回records?果集中的??；但是treebase?果集中按 （flat的真假），如果flat?真，与前面三种base相同，否?只保留isleaf的部分，意即除非是?的基?，否?不允?引用；而 TreeNode与Record是不同的；TreeNode使用另外getNode()方法。?于MemoryBase,SimpleBase在始始?入 ?存后就不需要pro和conllection&lt;br /&gt;   &lt;br /&gt;?于multibase:&lt;br /&gt;multibase??多?多基型??，目的仍是使用同一?基表，而避免?生多?表型?接。multibase基于一?simplebase???型，但 是??上的?例?象是一?dao.Multibase?象；在多?多?系表上可以使用simple_ref，也可以自行建立?系型表，如 member_role_ref;查??的方法先定?在Query中，然后得到逮?于某?基型的id是那几?，最后使用in()?句得到列表。?然，如果 ?目太多，sql?因?太?而不能?行。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-112737334289820993?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/112737334289820993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=112737334289820993' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112737334289820993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112737334289820993'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/09/hanvadatabaseservice.html' title='簡化多表連接的訪問方式，hanva中的database.service基表映射框架'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-112703567689181082</id><published>2005-09-18T02:27:00.000-07:00</published><updated>2005-09-18T02:27:56.896-07:00</updated><title type='text'>應用服務器看來應該避免多表查詢</title><content type='html'>一直沒有仔細考慮在自已的hanva框架中多表查詢的情況。今天算是真實碰到了，並不算太緊，這時侯正好可以較詳細地思考這個比較理論化的問題。事實上， 當表達層變得需要通過應用層去訪問數據庫時，如同J2EE試圖做到的一樣，單個的實體bean不會有太大的問題；而如果是條件性列表，就已經比較麻煩了， 如果是多表的話，原則上無法繼續。&lt;br /&gt;&lt;br /&gt; 原因就在於這種三層結構需要使用相應的預編寫的java類去承接查詢回來的數據。對於實體bean來說，對象就是數據記錄的虛擬反應，倒也沒有什麼區別； 但如果是多表連接的查詢，同時不應該每寫一個查詢需要特別生成一個java類（否則效率何在，還談何方便？），在邏輯上，基本上是說不通的；因為，那個反 應多表限制的類，它在實際意義上代表的是什麼對象呢？&lt;br /&gt;&lt;br /&gt; 目前對這種情況我是通過database外置基類加以解決，對於大多數情況下，基表只是一個小小的表，使用XML-內存映射的方式不但可以獲得更高的效 率，而且，還可以把絕大部分列表查詢簡化成高效率的單表查詢，（每一個表連接意味著多一次遍歷），並進一步地可以適應多數據庫的環境，實際運行效果非常 好。但這種代入內存的方式如果基記錄的數量很大，就不劃算了，效率也會直線下降，最終不如使用數據庫的傳統的多表查詢更為合理。&lt;br /&gt;&lt;br /&gt; 另一種辦法就是使用非規範性的操作，預先把本來需要實時多表連接產生的結果以非規範化的方式寫在相應的表記錄中，這樣，同樣可以把多表查詢簡化為單表查詢。事實上，這也是在系統優化過程中大量使用的提高運行效率的常用的方法。&lt;br /&gt;&lt;br /&gt; 使用上面這兩種方法，基本上可以避免產生真正的多表查詢，事實上，幾乎過了一年，才碰到可能需要多表連接的情況，就是一種證明；而且即使是目前的需要，也 是可以通過上面的第二種方法解決的。如果仍然想偷懶，那就直接採用傳統的操作sql/resultset的辦法，從而避開中間的應用服驄器的限制是也，也 仍然沒有必要把精力放在讓應用服務器適用多表查詢上。&lt;br /&gt;&lt;br /&gt; 無論是j2ee,hibernate,libernate難以真正成為開發的標准（得到４0%以上的應用），犯的一個共同的錯誤，就是把超過８０％的開發精力投入到實際上並不是必須多表連接上，實際上卻是降低了整個方案的可用性和適用性。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-112703567689181082?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/112703567689181082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=112703567689181082' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112703567689181082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112703567689181082'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/09/blog-post.html' title='應用服務器看來應該避免多表查詢'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-112653726429514701</id><published>2005-09-12T07:59:00.000-07:00</published><updated>2005-09-12T08:01:04.300-07:00</updated><title type='text'>壓縮生成jsp的數量，減少系統的編譯負載</title><content type='html'>近兩天為了搜索引擎橫沖直撞的故事，開始修正多jsp的框架。所謂多，是相對于過去重複性極高的servlet的方案而言的，實際上我的jsp重用程度高 到不能再高。如果說多，比起我見過的一般的jsp網站，jsp的數量一般只是他人的十分一以下。代碼量更是少得可憐，原因在于幾乎所有邏輯都已經封裝了。&lt;br /&gt;&lt;br /&gt;即使是這樣仍是有著再次壓縮的空間，而且，盡管重新達到整網一頁沒有必要，（那是使用servlet達到的，運行效果甚佳）,但依靠URL重寫的協助，整 網按功能在十來頁以來完成一個極複雜的多用戶多單位商業發布系統還是可以做到的。但問題來出現了，俺當初?什?要做到多目錄多文件自動複雜的JSP框架 呢？&lt;br /&gt;&lt;br /&gt;第一個原因很直接，那是因?沒有使用URL重寫這件武器；當時並沒有意識到這件武器結合一般的JSP可以?生如此威力；這個恐怕是最根本的原因；&lt;br /&gt;&lt;br /&gt;第二個原因是對于多用戶多單位達到可信賴的權限控制沒有把握，希望通過不同的目錄設置對應的環境常量設定達成絕對可靠的訪問控制——這條今天隨著使用體驗的加深，證明可以通過單目錄判斷也可以達到。&lt;br /&gt;&lt;br /&gt;第三個原因仍然存在，就是由于要保留多用戶多單位系統下的絕對自定義空間，需要提供獨立的文件目錄，在沒有URL重寫的協助，實際上不使用多目錄多文件是做不到的。&lt;br /&gt;&lt;br /&gt;唔，大概這是當初設定方案的主要考慮因素。從實際效果上看，在用戶不多，訪問量也不算太大的情況下，的確沒有什?問題；在用戶多，訪問量也大但是運行時間 已經不短的情況下，也沒有什?大問題；最大的問題大于剛剛完成升級到主服務器上或修改了關鍵文件時，大的訪問量造成多個文件同時編譯，而這些JSP文件一 般都會不同程度調用同一個組件，由此?生的編譯死鎖造成一至一次的發布失敗，需要重?甚至幾次才能度過這個發布後的震蕩期。&lt;br /&gt;&lt;br /&gt;這樣，就?生了必須加以優化，減輕發布後，以及維護性修改後，系統需要承擔編譯的消耗。如上所言，現在可以壓縮成若幹個高度重用的文件，這樣，無論負載量 有多大，?生編譯死鎖的機會成級數降低了。另外，原來不太注意引用的類別，現在也要注意一點了，根本實際的目的，嚴格使用最低消耗的方案：&lt;br /&gt;１、如果沒有變量共享，就不用file include;&lt;br /&gt;2、靜態內容文件使用c:import;這樣允許頁網人員任意填寫不會造成重新編譯的要求；&lt;br /&gt;３、動態內容但不具備變量共享的，使用c:import動態網頁或jsp:includepage（好象沒有什?區別），同樣可以縮小編譯請求的影響面；&lt;br /&gt;&lt;br /&gt;當然，最終的解決方案是完全實現靜態網頁發布。在完成靜態發布的升級以前，上述優化對于提供目前系統的承載量，估計還是有很大作用的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-112653726429514701?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/112653726429514701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=112653726429514701' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112653726429514701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112653726429514701'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/09/jsp_12.html' title='壓縮生成jsp的數量，減少系統的編譯負載'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-112558262423064608</id><published>2005-09-01T06:35:00.000-07:00</published><updated>2005-09-01T06:54:26.570-07:00</updated><title type='text'>在JSP中?构件的抽象和代?重用??以什么?度</title><content type='html'>這幾天在處理動態網站和博客的應用時，發現效率很低，其中的一個原因就是由于不得不在jsp的代碼層來來去去地進行很接近卻略有不同的編碼。在一般的習 慣，我會傾向于使用其同包含的代碼片結合變量實現重用，只要重複達到三次以上就值得這樣做。這次，有幾個原因令我手工重複處理而不是使用可用用的代碼片。&lt;br /&gt;&lt;br /&gt;第 一個原因是這裡重用的一般都是兩三次之間，而沒有出現三次；其次是近來的經驗發現大部分准備重用的代碼片也極少調用超過五次的，從而令我懷疑假想是不是 有誤；第三，當網站訪問量達到相當高的程度時，共用的代碼片很容易因為運行時編譯死鎖造成死機，令我進行重用性處理時要謹慎一點。事實上， tagfiles我已經完全放棄，就是因為這個原因。大量使用tag可以令javabean得到很好的調用和運行量賦值，但如果使用頻率不高而代碼比較簡 單，還不如直接在jsp中調用javalet實現，而不必追求代碼中的乾淨不含javalet。在這個手工處理可重復性代碼中，的確發現放棄重用而進行重 復工作是令人沮喪的，也是低效的。&lt;br /&gt;&lt;br /&gt;jsp的代碼可重用比較低的原因在於易於抽象的部分已經基本上包含在 javatag/javabean/EJB中，而不同的頁面最終總是在需求上遷移或多 或少出現不同，最後，就會出現邏輯上完全相異，以致於本來是為了重用節減開發時耗的代碼片重用，最後卻成了重復的編碼工作。&lt;br /&gt;&lt;br /&gt;既然加強重用 也可能帶來低效，完全在jsp代碼層單獨重復實現更是低效，那麼，重用的抽象應該以什麼度最合適呢？暫時總結出一個經驗，其中約有20％左右 仍帶有假設：javatag,javabean應該盡可能提供重用度，但以不帶有任何表達層代碼如 html為度;而在jsp層原則上應該以獨立編碼後，最後才考慮是否部分代碼在後面的編碼工作中可能會重用超過三次，以次作為重用化的標準。換言之， bean層是加強抽象，jsp層是放棄抽象，可能，會帶來更高的效率。&lt;br /&gt;&lt;br /&gt;而且，也可以很清晰地感覺到，這個原則由於團隊的組成成分不同也有所差別：如果是開發人員少而精，則應該采用更高重用性的開發方式；反之，如果低素質的開發員有一定比例，放棄高代碼的重用要求而接受更多的獨立代碼，開發效率反而會變得高一點。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-112558262423064608?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/112558262423064608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=112558262423064608' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112558262423064608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/112558262423064608'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/09/jsp.html' title='在JSP中?构件的抽象和代?重用??以什么?度'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111916124941240513</id><published>2005-06-18T22:50:00.000-07:00</published><updated>2005-06-18T23:07:29.420-07:00</updated><title type='text'>微軟新版XML格式與GNU不相容 阻擊開源軟件(不見得能成功)</title><content type='html'>&lt;span style="font-weight: bold;"&gt;牛虻說：&lt;/span&gt;&lt;br /&gt;         也許不少人沒有看懂這則新聞，有可能這是影響未來五年IT行業最重要的新聞之一。一直到昨天，仍然有人就XML、HTML的長長短短跟牛虻爭個不休，牛虻 這裡再次強調：XML/HTML不是同一層次的東西，實際上，HTML就是由W3C提供了視覺解釋標準的一種XML；XML要發揮作用，比自定義標簽更重 要的是解釋這些標簽的程序和方法，這就構成了對XML的專利。如同每個人都可以用漢語取名，漢語不是任何人的專利，但名字原則上卻是人獨有的，牛虻可以定 義&lt;牛虻&gt;是一個大色狼&lt;/牛虻&gt;，因為它的所有權是牛虻的，但別人這樣做，牛虻恐怕有希望拿到一筆精神賠付呢！&lt;br /&gt;        微軟的Office是微軟的最主要收入來源，超過了操作系統，超過了數據庫，超過了其他任何東西，盡管，桌面操作系統才是微軟壟斷優勢的基礎。微軟把自已 的下一版Office建立在XML內容定義後的解釋上，不但微軟對解釋程序具有專利權，而且，對微軟自已定義的標簽含 義也具有專利權，他們不得按這種標簽開發相應的xslt和解釋程序。這樣，就把下一代使用微軟的Office的用戶死死綁定在微軟的賺錢機器上——但不要 以為這是非法的，微軟完全合法，甚至……牛虻覺得它是合理的。&lt;br /&gt;       在牛虻的眼中，用戶是比較蠢的，特別是中國大陸上的用戶是世界上比較蠢的那種用戶——免費為微軟搞低價傾銷還以為佔了微軟的便宜，還為微軟叫好，拿著些個 把微軟的IE包裝一層皮卻消耗多幾倍資源的IT或者另一種什麼MXXXX瀏覽器（忘了名字，反正記得特垃圾），卻比說比firefox這樣好那樣好——說 真的，firefox也沒有什麼好的，但牛虻使用它已經半年了，沒有一次彈出窗口：“發生錯誤，窗口關閉，將重啟IE，是否發送錯誤信息？”，而IE呢？ 呵呵，目前是平均一天一次。這是為什麼呢？不是微軟的技術差，而是因為微軟已經把網景送進了地獄了，它乾嘛要做得這麼好？可以想見，一旦微軟通過標簽專 利，同時又得到盜版的支援打擊了潛在的對手的競爭能力，那麼微軟賺得最豐厚的市場之一，就是中國市場，那一批蠢得豬一樣的卻以為天下最聰明是他們的盜版 友。&lt;br /&gt;       但其中有一個變數，是微軟可能沒有考慮進去的，作為桌面霸王，微軟似乎下意識不願意承認一個事實：辦公軟件已經基本上夠用了，網絡共享的文件編輯和文件存 儲會令更精致的桌面辦公軟件變得更過時：如同二戰的戰列艦是最好看的，也是最過時的。道理是一樣的。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;微軟新版XML格式與GNU不相容 阻擊開源軟件&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;新浪科技訊 美國東部時間6月18日(北京時間6月19日)消息，微軟即將推出新版Office Open XML格式，其免版稅許可證與GNU通用公共許可證不能相容。通過這種方式，微軟就可以阻止開放源代碼軟件使用這種格式。&lt;br /&gt;&lt;br /&gt;　　美國一位高級專利官員正在就微軟的這一行動提出質疑，他認?微軟的這種許可證在合法性和可執行性方面都有待商議，並暗示免費和開源軟件開發商不用理會微軟的要求。&lt;br /&gt;&lt;br /&gt;微 軟于2003年底首次發布了Office 2003 XML參考描述語言(Reference Schemas)。微軟Office部門官員本月早些時候表示，他們計劃使這種新的XML文件格式成?Office 12的默認值。明年，擁有免版稅許可證的用戶可以使用到Office 12。&lt;br /&gt;&lt;br /&gt;　　但是，免費軟件基金會總裁和GNU GPL的制作者理查德-斯多勒曼(Richard Stallman)已經明確表示，免費軟件團體通過微軟的活動不會獲得任何利益。他認?，微軟提出的這種新格式，意味著用戶對處于這種許可證下的程序不能 進行任何修改。他說：“修改軟件的自由和發行修改軟件的自由，是定義免費軟件的兩種最必要的條件。如果這兩種自由被限制住了，那?這種軟件也就不是真正的 免費軟件”。&lt;br /&gt;&lt;br /&gt;　　微軟XML設計部門高級經理吉恩-帕?(Jean Paoli)稱：“微軟已經承諾要開放XML文件格式，那?就一定會這樣做。而我們也正在采取相應的行動。但是，使用這種XML文件格式的人，也不能將其 用于自己的程序。也就是說，處于通用公共許可證下的Linux以及其它的開源軟件，不能使用微軟的這種文件格式。”(飛雪)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111916124941240513?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111916124941240513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111916124941240513' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111916124941240513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111916124941240513'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/xmlgnu.html' title='微軟新版XML格式與GNU不相容 阻擊開源軟件(不見得能成功)'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871940906909455</id><published>2005-06-13T20:18:00.000-07:00</published><updated>2005-06-13T20:23:29.076-07:00</updated><title type='text'>應該如何使用標簽技術？使用EL，logic和hanva標簽庫完成複雜的後台處理功能的JSP示例</title><content type='html'>&lt;p&gt;JSTL標簽是SUN帶頭與apache社區合作的?品，可惜從一出現就已經是一個過時的技術。SUN的軟件架構師似乎缺乏從顧客角度考慮技術取向 的能力，與微軟相比差之千?。就標簽技術而言，它的目的是令菜鳥中的菜鳥變得可以寫JSP，還是令一般程序員寫JSP顯得更方便，更好管理？顯然，SUN 的那位笨蛋架構師沒有想明白這個道理（越是看得多它的文檔介始，越是覺得那個家夥是個大笨蛋)，把SUN數千名天才工程師的才智白白浪費了。&lt;/p&gt;  &lt;p&gt;所有人都已經知道，JSP出現的目的就是?了讓程序員更方便地寫簡單的servlet,複雜的多功能的servlet是不容易用JSP實現的。而 JSP希望讓菜鳥寫java動態頁面的目的並沒有達到，這條，還不如ASP/PHP。在JSP中散布底層業務邏輯既不便于對象組織，也不但于代碼管理，非 常低效。這是發展出javaBean和標簽技術的原因；而JSTL呢，它的基本客戶邏輯竟然是?了幫助使用者更方便地把底層代碼散布在JSP上！？包括數 據庫連接？！所以這東西是一個新的技術實現落後目標的?品，面對市場需求整整慢了一拍。&lt;/p&gt;  &lt;p&gt;唯一有點價值的是它的循環邏輯，這條還是很有用的。只不過能夠實現的不止它一個，struts.logic標簽就是很好用的一種，而且不用指向 http:/sun.xxxx/core什?的，事實上JSTL能夠提供的struts:logic也能夠提供。實際上struts幾個標簽庫中也就 logi,有點價值，bean也可以，其他的html是純粹和FormBean?核心的MVC設想框架提供的。即使這樣，就實用性而言， strutslib仍比sun實用得多。&lt;/p&gt;  &lt;p&gt;struts標簽庫不能很好地面向數據對象，這是它的不足，hanva標簽就是?了補充這個不足。結合struts的logic庫，使用hanva 標簽可以達到在jsp中聲明和接收變量，可以實現多種邏輯，可以直接從底層獲得持久性非持外性的數據對象，處理並輸出——一個程序大致也就只有這些東西做 的。特殊的東西再特殊處理，直接完全使用標簽調用下層服務daemon程序完成絕大部分功能，已經可以做到了。&lt;/p&gt;  &lt;p&gt;下面的論壇示例刪除程序是這樣的一個功能，可以處理任何的實現了hanvaDAO接口規範的表數據的刪除，包括對其相關數據記錄的同步處理。它接收 一個對象類型(ent)，及ID，判斷這個對象（行記錄）是否存在，然後判斷它的sourceid和id是否一致（是主貼還是跟貼），如果是主貼，就把它 的從貼一起刪除，否則就只刪除當前貼，然後返回原來調用的一頁，如果出錯，就轉向到errors.jsp頁，顯示出錯信息。&lt;/p&gt;  &lt;p&gt;&lt;entity:present ent="${param.ent}" oid="${param.oid}" id="thent" nexto="${header.referer}"&gt;&lt;br /&gt;    &lt;%--如果記錄存在就繼承內嵌邏輯，把該記錄定?ident名--%&gt;&lt;br /&gt;    &lt;%--判斷sourcid與id是否一致--%&gt;&lt;br /&gt;  &lt;logic:equal name="thent" value="${thent.sourceid}" property="id"&gt;&lt;br /&gt;&lt;%--取所有主從貼，集合定名?theobjs--%&gt;&lt;br /&gt;   &lt;entity:entities ent="${param.ent}" id="theobjs" qstr="sourceid=${sourceid}"&gt;&lt;br /&gt;&lt;%--?代集合內容，單個取名?theobj--%&gt;&lt;br /&gt;     &lt;logic:iterate id="theobj" name="theobjs"&gt;&lt;br /&gt;&lt;%--刪除該對象--%&gt;&lt;br /&gt;      &lt;cmd:delete ent="${param.ent}" target="${theobj}"&gt;&lt;br /&gt;     &lt;/logic:iterate&gt;&lt;br /&gt;   &lt;/entity:entities&gt;&lt;br /&gt;   &lt;/logic:equal&gt;&lt;br /&gt;  &lt;logic:notequal name="thent" value="${thent.sourceid}" property="id"&gt;&lt;br /&gt;&lt;%--單個從貼，清除該對象--%&gt;&lt;br /&gt;    &lt;cmd:delete ent="${param.ent}" target="${thent}"&gt;&lt;br /&gt;   &lt;/logic:notEqual&gt;&lt;br /&gt; &lt;/entity:present&gt;&lt;/p&gt;  &lt;p&gt;標簽結束，根據nexto轉向到調用者，這樣段小代碼實際上就扮演了一個MVC中的c角色。如果需要輸出斷點，可以調用hanva:log 把實時內容輸出到log日志中。一個比較複雜的功能就此完成了。全程實際上只是進行了一次或兩次數據庫的訪問，如果是多個從貼，需要獲得它的串，這是可能 的第二次。注意&lt;entity:entities&gt;標簽，它輸入一個條件，也可以輸入fields選項，得到一個ArrayList串（沒有 同步要求就不用Vector），如果不是?了翻頁，它可以代替hanva:list，使用上也更方便，沒有需要先設定一個dao.list對象。&lt;/p&gt;  &lt;p&gt;我認?這才是標簽技術的真正用法：幫助程序員在界面清晰明確地調用後台的處理程序，方便面向對象的業務邏輯的建立，方便隱藏非表達層的邏輯;而不是變成把頁面搞得更複雜，堆上更多難懂代碼的又一套新方法。&lt;/p&gt;  &lt;p&gt;相對而言，tags文件標簽技術顯得更現實一點。如同jsp是方便菜鳥（仍是程序員）寫簡單的servlet一樣，tags標簽文件是方便看到 Class就發抖的菜鳥象寫jspjavalet一樣寫標簽；顯然，是最簡單的SimpleTagSupport的變種，只有它才有一個體內容。也同樣， 充分利用Class類結構的編碼技術在這?沒有辦法實現。&lt;/p&gt;  &lt;p&gt;JSP開發社團看來熱衷于在局部別具一格地提供一些局部方便性措施，卻常常忽略了客戶更大的一個要求：在項目開發中盡可能采用單一的標准的範式完成 所有程序。多使用一種小技術模式在局部方便了，全局來說卻是多管理一種一種技術，或者說程序員要多學一種只在局部有效的技術。這個邏輯錯誤從J2EE開始 就伴隨著SUNJAVA的技術發展，看來是它的不治之症。在筆者看來，與其多搞小動作，不如在核心一鑽到底，而小範圍內的方便措施，還是有有能力的客戶去 實現?佳。拙劣地模仿微軟去拍落後（也是非主流的客戶）的馬屁，將是SUN公司技術上最終失敗的原因。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/24/360540.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/24/360540.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/1431465.html"&gt;http://zwwwxy.blogchina.com/1431465.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;p&gt;&lt;a href="http://javaxml.blog-city.com/ellogichanvajsp.htm"&gt;posted Tuesday, 14 June 2005&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871940906909455?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871940906909455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871940906909455' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871940906909455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871940906909455'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/ellogichanvajsp.html' title='應該如何使用標簽技術？使用EL，logic和hanva標簽庫完成複雜的後台處理功能的JSP示例'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871910122030170</id><published>2005-06-13T20:17:00.000-07:00</published><updated>2005-06-13T20:18:21.223-07:00</updated><title type='text'>減少jsp文件目錄的維護成本，需要一種什?樣的JSP發布框架?</title><content type='html'>&lt;p&gt;即使對于一個大部分基本邏輯都包裝在標簽/類/servlet/EJB中的網站，以至于在jsp中看不到任何的javalet代碼，隨著規模的擴大 和項目時間的延長，目錄中總是堆滿了越來越多的垃圾文件。有些文件本身不是垃圾，而是被包容的子文件，但是jsp服務器可不管這個，如果不是jsp後綴， 它就會被jsp把源代碼下載到客戶端；或者，同樣是jsp一樣時就讓維護者頭大。如果不是采用良好的文件策略，那?隨著規模的擴大，一般的中大型站點堆出 幾千上萬的jsp文件，其中每一個模塊分上幾十個，是非常正常的；這時侯，管理這些文件就成?一件艱苦的工作；事實上，如果不是多人分管的話，一個發布管 理員真正能夠維護的文件如果超出一百個，效率就會急劇降低。何況，還有更重要的sql文件，class文件，xml設置文件……。?什?總是努力使用 bean/fragments/標簽/ORclass（如EJB），這就是原因之一。事實上，從事過大型項目的開發員對于後期目錄中那種不知那個有用那個 無用但卻要?不管要?只能一個個識別的經曆，總是一種難言的痛苦。經曆過這種痛苦也會對可重用組件在項目中實際上降低了後期維護費用的感受良深。&lt;br /&gt;        要實現高度的重用性，減少需要維護的文件的數量，就需要對系統架構甚至前台框架都進行抽象，重用的方式除了Class等方式外，還可以使用  shellscript幫助，特別是對那種必須分割出目錄管理而實際上結構非常相似的類型。通過這個辦法，即使是很大的項目，也可以把需要維護的jsp文件，不含java類庫壓縮到一百個以下，包括用于包含的小jsp片片fragments。&lt;br /&gt;    良好的命名規則可以進一步提高對文件的識別，也便于使用shellscript按文件類型進行管理。?了防止被jsp服務器下載到客戶端，如果是與 apache結合的話，可以在apache中建立禁止下載的文件類型。我一般是把這種文件命名?jsp_，?了達到這種命名的規範性，甚至不惜把已經寫好 的程序改一遍，幸好，在良好的組織框架下，文件總是只有幾十個，並且只需要改一兩行的幾個字母。盡管如此，每次都仍是讓我感到生畏，這種規範工作的確是最 不令人興奮的。&lt;br /&gt;    建立良好的命名規則和目錄結構，也是?了可以有效重用已有工作的前提，但什?時侯應該達到重用呢？畢竟即使是很相似的框架類型，在面向重用要求時，就意味 著很多的if-else。logic:equal/present之類，在Class中可以通過接口和繼承實現代碼的高效率，而在JSP中，如果重用變型 達到三個以上，大量的if-else之類就令混帳代碼冗余廣泛伸延，而在jsp文件內部令維護難道大大增加一個檔次；或者一個簡單的要求就需要 include十次八次，同樣是加大了維護成本。（要知道，接手者，甚至是自已吧，過了幾個月，對于開發中的印象早就消失幹淨了。）&lt;br /&gt;    這是一個難以協調的問題，可以調整的空間很小：如果不重用而一個文件任務專用，意味著每次需求變動時要重複維護多個非常相近的文件；超過三個的話，也就等 于說這個文件建立方式是低效的。而如果文件複用的話，依靠在jsp中的判斷實現，那?文件變得難以維護調試的界限也是三個左右。希望把這種代碼包含進 Bean是愚蠢的選擇，Bean不是做這些事情的，原則上，非表達層只應該包含業務邏輯，不應帶有任何專用的表達層代碼，象html。&lt;br /&gt;    問題的焦點在于，JSP作?表達層的實現方式，本身缺乏對象抽象的能力，只能依靠在jsp中的邏輯判斷適應條件變化；而理想的MVC，view視圖需要的 是一個定義視圖表達形式的對象，jsp根據這個對象的設置生成框架需要的html代碼，甚至生成jsp本身。因此，實際上對于這種大型的站點來說，在數據 庫以及數據映射和業務邏輯的中間層以上，表達層以下，需要的是一個jsp的發布系統。這個發布系統根據用戶自已定義和開發的框架抽象，生成jsp目錄/文 件等。它到底應該如何運行，我還沒有明確的解決方案，不過這個系統會有用的。&lt;br /&gt;    Cocoon是另一種發布系統，不過不符合這個要求，他事實上是一個與目錄無關的xml轉換器，可以根據用戶定義的xslt轉換器以及客戶請求的文件類 型，通過不同的轉換器向用戶提供同一內容的不同文件類型，xml,html,pdf或者其他。事實上，由于在互聯網上存在著文件類型統一化和歸一化的自然 趨勢，因此，?了少量用戶的特殊文件類型要求讓系統增加一半成本，減慢一半以上的速度，只能處理少一半的文件，加了這?一個轉換層是否值得我是深表懷疑。 象特定類型的數據必須提供xml，（如SOAP），直接用servlet寫的應答程序就可以看作是一個全功能的轉換器，又何必另外再搞一個轉換器和控制器 來處理這種要求呢？除非所有文件都必須同時提供 xml/html/pdf，否則象cocoon這種框架，我相信是毫無意義的。&lt;br /&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/26/364322.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/26/364322.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/1340936.html"&gt;http://zwwwxy.blogchina.com/1340936.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/jspjsp.htm"&gt;http://javaxml.blog-city.com/jspjsp.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871910122030170?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871910122030170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871910122030170' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871910122030170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871910122030170'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/jspjsp.html' title='減少jsp文件目錄的維護成本，需要一種什?樣的JSP發布框架?'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871854897130972</id><published>2005-06-13T20:00:00.000-07:00</published><updated>2005-06-13T20:09:08.976-07:00</updated><title type='text'>MVC實現中控制器servlet向jsptag轉變後參數維護方式的考慮</title><content type='html'>&lt;p&gt;MVC模式提供了標准的表達層和業務層邏輯分離的模塊建立的原則，不過在JSP中實現MVC要面臨無狀態的環境，而狀態維護是MVC模式實現的前 題。因此，維護MVC中的狀態成?實現MVC/JSP時的最大難題和成本構成因素之一，它的缺點在struts項目中顯露無遺。狀態維護的困難最終表現? 多步控制參數維護上的困難，OPflow提供了一個試圖面對流程對象進行維護的方式，但隨著JSP標簽的出現，令JSP MVC中的C有可能更適宜用標簽實現，又進一步令整個JSP/MVC實現方式面臨又一次的檢討，但也可能是一次進步。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;OPflow本質上是?了在WEB應用中實現MVC控制流而設計的。對于WEB應用中是否應該使用MVC模式，在技術社區中仍然存在很大的 爭議；而針對在網上兌現MVC模式的一些典型框架，象.net以及java的struts，在實際應用中都顯得不盡如人意，常常是得不償失。MVC在 WEB應用中的 Module問題上基本上達到了分層按功能劃分組件功能，V視圖部分以脫離業務和底層邏輯的方式顯視，這兩點都已經沒有太大的爭議；焦點在于C，如何定義 C？如何在沒有嚴格狀態保留的情況下安全地使用C控制器？在MVC模式中如果控制器每個操作，象每個servlet.action.do,都只是針對一個 目的對象（象一個訂貨記錄）的一個操作，那?也就失去了MVC的實際意義.把實際處理功能放在再下一級模件中實現倒也是一個妥協的辦法，不過，結竟那不是 正道，因?，這?討論的是是不可以使用MVC提供軟件開發和運行的效率。所以在實際操作中都是使用一些傳遞的參數，象"act"告訴控制器類型，通過變更 不同的參數從而進行不同的控制，以達到最大效率的代碼功能重用；這不一定是最大程度的功能組合，到底重用到什?程度合適，我覺得需要的實際的工作中按項目 要求進行微調。&lt;/p&gt;  &lt;p&gt;同樣的邏輯也存在于V視圖上。如果開發者希望自已的視圖部分成?一個顯示框架(微軟的word,甚至是?覽器就是一個顯示框架)，而不是每一種顯示 對象的每一種細節都必須是一個程序的話，也必須是根據不同的指示參數提取不同的內容，以達到最大效率的和最低成本的模塊重用。這樣，無論是C還是V，如果 不想讓自已的開發變成隨機延伸的數不清的功能過分單一又過分相似的C和V，就將面對著另一個困難：處理一連串的act參數。而這些參數一般情況是放在 request.parameter中傳遞。在與一些版友的討論中發現一些朋友會混淆參數所存的命名空間，我認?，session一般用于會話跟蹤的參 數，而不應與界面關聯；而application應該是全系統的公共變量；同理，pageContext應該是僅止于當前頁面；如果不明確這個命名空間， 會把自已投入參數混亂的陷阱。&lt;/p&gt;  &lt;p&gt;由于WEB應用不存在象VC++/VB/JavaSwing那樣的單一運行時狀態保持環境，所以當出現多步操作而必須共享部分變量空間時，大致只有 兩個辦法：一是在session中建立面向操作上下文（對象）的helper，二是在request過程中維持多步的狀態變量一致性。前者是較通用的辦 法，但缺點也是明顯的，就是每一種操作都要考慮一種helper,然後使用Vector,arrayList但集合類型地變量進行維護；顯然， struts中的 formBean和DynaFormBean,就是這樣一種helper。後者如果沒有一些工具幫助的話，在多步操作中要維持變量一致性簡直就是一場惡 夢。而Oplfow就是這樣一種工具。&lt;/p&gt;  &lt;p&gt;hanva.Opflow的設想是使用一個外置的xml文件，把界面的操作形式看作是一種對象，定義?flow，每一步操作對應的URL看作是 flow的一個元素step，通過判斷所在的step，按約定方式組織各個環境的變量，包括變量的邏輯轉換，象垃圾回收站中deleted將取反之類。在 它的幫助下，可以把不同的頁面輕松組成一個個一步接一步自動維護的WEB功能模件。設想合理，實現後的運行也很理想，不過在運行一段時間後，仍發現有不足 之處。&lt;/p&gt;  &lt;p&gt;其一，是xml的修改必須重?應用才能重新載入內存；其二，對于頁面人員來說，""這樣的路徑顯得不太直觀。第三；這不是OPFLOW直接的問題： 在面臨權限控制時，基于action的控制器不便實現與jsp同樣的界面控制邏輯。後面這一條可以作進一步的解釋。這是指在WEB上開放的連接，理論上是 說所有人都可以同步訪問的，無論它是V 還是C，只需要符合相應的條件，就可以實現操作。如果不能解決這個問題，那?WEB應用本身沒有可靠性可言，但如果解決方式過分複雜，象每一個程序進行一 次複雜的PMI驗證，然後最後兩句執行實際操作，這樣WEB的性能很差，而且整個項目開發的工作量會成級數的倍增。解決這個問題的關鍵在于共享單一變量空 間（會話helper是一種方式，不過缺點有如前述），並由一個共用的訪問驗證組件完成驗證。由于這樣的組件是複雜的，如果在一套系統上維持兩套達成同樣 功能但機制不一的PMI組件，那?程序開發和維護成本也會成倍數增加。&lt;/p&gt;  &lt;p&gt;Jsp標簽提供了解決這個矛盾的一個途徑，並且，在此前的文章中已經提取，jsp標簽可以看作是一種在jsp中行的可運行時配置變量的 servlet，理論上可以由servlet實現的controler也可以由jsp標簽完成，並且，它較servlet可以訪問jsp上下文空間，從而 能夠實現與jsp訪問PMI控制同樣的邏輯。這是我決定把servletcontroller逐步轉向標簽controller的原因，盡管標簽仍沒有解 決jsp難以維護頂級模板的缺陷。不過，這就影響到MVC中關鍵的C的角度，並且，實際上是把V與C使用同樣的技術方式（標簽）作?統一媒介加以實現了， 從而也必然影響到 OPFLOW。這樣一來，我的構件JSPWEB應用的整個項目基礎模式就出現了變化，雖然很可能是進步，但模式的成熟總是需要一些波節，它的優點和缺點也 必須在使用過程中才能真正體驗出來。&lt;/p&gt;  &lt;p&gt;原來以?JSP控制器標簽的使用會大大降低opflow的必要性，因?opflow的其中的一個目的是彌補servlet不能方便地調節運行參數而 開發的;而調用控制器標簽的jsp頁面本身也可以作?參數調節的空間，這樣opflow的必要性是不是就減低了？但實際使用時卻發現對于運行時過程參數的 維護，opflow還是很有必要的，除非在標簽中集成原來的維護參數的底層代碼，這是可能的，因?隨著標簽的使用，jsp數量的增加已經不意味著太大的維 護量，它們實際上只是一兩個標簽的載體。至于如何合在一起使用才最高效，還需要在應用中慢慢總結，歸納出一套可靠高效的程序模式才算對得起自已此前的工 作。&lt;/p&gt;  &lt;p&gt;從當前的情況看，操作標簽是對servlet控制器的更替而不是對opflow的更替，標簽本身不能簡單地實現低成本的參數維護；不過，在單一步驟 時，這是無意中發現的，由于ActionTag是使用了與Struts.ActionServelt同樣的轉向代碼，我並且加進了從若?空就從 header中取 referer的部分作?轉向目標；這樣一來，無意中就令單步操作在操作完畢後反回了同條件參數的顯示頁面——顯然，把標簽直接寫在這些頁面上也可以達到 同樣的效果。不過需要在標簽生效前先用logic.prisent之類的判斷一下是不是要先進行標簽標定的業務操作。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/13/345658.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/13/345658.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/1185354.html"&gt;http://zwwwxy.blogchina.com/1185354.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/mvcservletjsptag.htm"&gt;http://javaxml.blog-city.com/mvcservletjsptag.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871854897130972?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871854897130972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871854897130972' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871854897130972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871854897130972'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/mvcservletjsptag.html' title='MVC實現中控制器servlet向jsptag轉變後參數維護方式的考慮'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871800118274062</id><published>2005-06-13T19:59:00.000-07:00</published><updated>2005-06-13T20:00:01.196-07:00</updated><title type='text'>apache/tomcat的JSP?URL重?的SEO优化/二?域名的要?</title><content type='html'>&lt;p&gt;Apache是用了很長時間，但也只是用了很長時間，要說精通還談不上。所以這四五天存在著補課的味道在?面：既然公司不能提供好的系統管理員，也 只能是自已兼任了。經過對Apache和tomcat結合後的進行SEO優化的處理，四五天後，對這幾件工具的基本邏輯框架有了統一的認識。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;對URL重寫的了解需要是針對這樣的需求：偏向于HTML的SEO搜索引擎優化，以及提供不定量的二級域名便于模塊管理和推廣。搜索引擎不 能識雖動態頁面在技術上是不可能的；我認?最大的可能在于對于靜態的hardlink，如果不存在搜索引擎會得到一個404標識；而對于動態頁面，反應就 不一定了。這樣就不便于搜索引擎對索引維護和分目。&lt;/p&gt;  &lt;p&gt;對Apache mod_rewrite的深入了解後，發現在它的文檔和介紹文章中常常缺少幾個關鍵性的導引；而過快地涉及到具體的細節。要理解mod_rewrite的 工作，首先是要理解，mod_rewite是針對目錄進行工作的。換言之，每一個目錄的RewriteRule是各自獨立的，每個目錄的重寫既是最高層的 容器同時也是最低層的容器，因此，RewriteRule定義的地方是在各個目錄所在的位置，或者是所在目錄的.htaccess中。&lt;/p&gt;  &lt;p&gt;其次，mod_rewrite是缺乏邏輯功能的平面型規則集合，因此每一個目錄設置中都是每一條規則地進行重複性轉換，[L]僅僅是表明一次匹配結 束，它還需要重新匹配，直接沒有任何條目與之匹配後才會輸出請求，這樣，如果規則稍多不但性能會直線下降，而且還很容易陷入混亂，所以 mod_rewrite要慎用，使用mod_rewrite來匹配二級域名要小心。對此，mod_rewrite設計者是期望使用正則表達式匹配，或允許 用戶調用perlShell作?複雜匹配邏輯上的應用。但這樣就令開發變得複雜起來了。&lt;/p&gt;  &lt;p&gt;由于 mod_rewrite是基于目錄級的，所以它的優先級低于虛擬主機設置；而VirtualHost主機的優先級也低于 VirtualDocumentRoot的泛虛擬主機設置。由于VirtualHost的ServerName基于IP頭的匹配不能使用正則表達式，因 此，使用VirtualDocumentRoot設置多級域名存在著非常大的限制,應用稍微多元化就會面臨著難以克服的沖突。因此，單純使用虛擬主機或者 是URL 重寫都是不太有效率的，這時侯主要路徑應該是使用html導引，這樣既可以滿足SEO喜歡hardlink的要求，也不會影響到使用者的?覽；最重要的 是，可以把主要解決方案集中到一個應用程序的範籌，簡化了項目技術，也就降低了項目的成本。&lt;/p&gt;  &lt;p&gt;使用mod_rewrite和二級域名的站點基本上使用php大概是基于這樣的原因：會話的一致性維護。當mod_rewrite應用到jsp站點 時存在著很大的複雜性。由于mod_rewrite是針對目錄進行的，它必然幹擾到目錄的運作；而jsp的上下文由于根據基礎目錄作?應用程序的判斷的； 這樣，在目錄清晰的情況下，jsp在不同的域名和虛擬主機下面都能正常識別到所維護的會話，但一旦目錄不齊全，象使用二級域名，無論這個目錄解釋是來源于 URL重寫還是虛擬主機設設置，?覽器都會把它看作是兩個會話請求，從而造成混亂。因此，在jsp站點使用二級域名，除了使用硬的html連接導引外，別 無它法。當然，使用Redirect方式可以解決問題的，表面上，但這樣的話就失去了SEO的意義；而URL重寫本來就是?了SEO而進行的；那?又何必 搞重寫呢？&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;截取RewriteCond條件中的字符串作?改寫變量：&lt;br /&gt;RewriteCond %{HTTP_HOST}  ^([A-Za-z0-9\-]+)\.bbs\.home\.javanet\.edu$ [NC]&lt;br /&gt;RewriteRule ^$ &lt;a href="http://home.javanet.edu/_apphome/bbs/%1.html"&gt;http://home.javanet.edu/_apphome/bbs/%1.html&lt;/a&gt;  [L]&lt;br /&gt;注意其中的()和%X，前者是正則表達式截取的內容，後者是按順序取變量；&lt;/p&gt;  &lt;p&gt;截取RewriteRuld中URL的字符串作?重寫變量：&lt;br /&gt;RewriteRule ^([A-Za-z\-]+)\.html  /apphome/$1.jsp [L]&lt;br /&gt;同樣地，注意它的()和$，後者是與ReWriteCond不同的地方。&lt;/p&gt;  &lt;p&gt;另外要注意的是[L]，盡管是鏈中最後一條，但與防火牆的過濾轉發規則鏈不同，這個L是本次循環結束標志，而不是整個改寫流程結束標志。重寫的邏輯是：&lt;br /&gt;while(有沒有任一條匹配)  loop;&lt;/p&gt;  &lt;p&gt;而防火牆規則鏈是if-else-else......；&lt;/p&gt;  &lt;p&gt;特別是象本人一樣開發過防火牆的，對這種規則的區別要特別注意，否則很容易陷入死循環。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/1149090.html"&gt;http://zwwwxy.blogchina.com/1149090.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/09/340996.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/09/340996.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/apachetomcatjspurlseo.htm"&gt;http://javaxml.blog-city.com/apachetomcatjspurlseo.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871800118274062?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871800118274062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871800118274062' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871800118274062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871800118274062'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/apachetomcatjspurlseo.html' title='apache/tomcat的JSP?URL重?的SEO优化/二?域名的要?'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871741340938688</id><published>2005-06-13T19:49:00.000-07:00</published><updated>2005-06-13T19:50:13.416-07:00</updated><title type='text'>選擇jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯誤</title><content type='html'>&lt;p&gt;許多人認?JSP是JAVA向微軟ASP挑戰的成功?品，到今天，圍繞著JSP方案發展出了TAG/EL等技術，JSP作?JAVA的BS前台界面 方案看來已經是無法逆轉。但在我看來，JAVA選擇JSP這種表達形式，恰恰是它最失敗的地方，是對ASP的一種拙劣的模仿，它本來可以做得更好的，甚至 可能據此讓微軟徹底退出服務器領域，但最終，卻可能成?足以令JAVA最終失敗的重大戰略方向性錯誤。&lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;p&gt;&lt;br /&gt;JAVA到今天仍具有微軟所有語言所不具備的優點，就以C#而言，只不過是形似而神不似。java最根本的地方不在于它的OOP，不在于它 是C++的語法優化，這些都不重要，而在于它的虛擬機機制，使它成?最佳的跨平台的服務器語言；而C#無論多?語法相似，都無法改變這樣一個現實：它只是 微軟CLI中的語言中的一種，它再成功，也充其量是取代了在windows運行的JAVA；某種程度上，C#是一種注定沒有必要存在的語言，在CLI中， 只需要一種就夠了，象VB.net。&lt;br /&gt;JAVA到軟件世界帶來的最大的影響是令軟件真正出現了分層開發，出現真正的三層結構。盡管有些家夥吹噓他們的軟件是N層結構（真不要 臉！），其實究其實則，都只不過是傳統的CS式的兩層結構的變種，不能把函數每加一個就稱?一層噢！JAVA出現體現了軟件的創造性思維，但JAVA犯的 錯誤最大的地方就在于他毫無創造性地模仿了ASP，並且，竟然把JSP作?中間件的主要訪問手段加以發展。這是一個重大的失誤，也許，如果有一天JAVA 死掉的話，就死在這個失誤上面。&lt;/p&gt;  &lt;p&gt;ASP的是模仿最早的livewire式的jsp和cofusion，livewire也是本人最早在項目中接觸的jsp，與後來的java jsp毫無相同之處。這種netscape公司的"jsp"與asp有共同的特點，就是完全沒有面向對象的特性，是純粹的解析性腳本語言，後來的PHP也 是這樣的?品，PHP本質上可以看作是Cscript。這些語言的出現原意是要滿足那些不懂計算機語言，從HTML美工轉行的半吊子程序員的能力需要，美 其名?讓美工可以寫動態網頁程度。不過，這個開發假想成了互聯網出現以來最大的笑話之一，美工式的程序員始終不能寫真正的動態網頁，反而讓真正的程序員去 做了美工的活了，最典型的?品就是struts。&lt;/p&gt;  &lt;p&gt;java與此完全不一樣，它是一種需要編譯的語言，具有完全的面向對象的能力；所以，它如果能夠發揮這種特點，打敗其他的幾種腳本是毫無困難的。結 果，SUN的天才的笨蛋們（我覺得這種稱呼最客觀，既是天才，也是笨蛋），選擇了用坦克車去和捷達爭奪出租車市場，做起了JSP。而我認?， servlet才應該是它最佳的發展方向。今天，我已經忘記了當初是什?原因令我放棄了jsp而使用servlet作?項目解決方案的；只記得後來完全放 棄jsp是由于兼顧兩種形式在傳遞變量和地址時非常複雜，還不如光用一種。今天當我以?我當初錯了，而標簽/EL等技術的出現會令JSP不同往昔而再次在 重大項目中選用JSP時，（其中一個原因也是那個笑話的延續，希望不懂JAVA的維護人員可以在交貨後自已維護系統前台），隨著項目的進入，我記起了當初 放棄JSP的原因：一個是當時的代碼管理非常困難，JSP系統基本上與其他PPP類程序一樣是不可維護的；另一個原因就是JSP無法基于模板進行維護。前 者由于tag等的出現而緩解了，（從前也可以使用include sevlet的辦法達到接近的效果），後者仍然一樣，關鍵就在于不能複蓋已有的代碼。而在servlet中，重載一個方法是很容易的。&lt;/p&gt;  &lt;p&gt;許多人以?servlet難寫，在doget/dopost/init/等中需要塞進那?多的方法；其實，這是一種誤解，這種誤解是沒有認識到 servlet本質上是一種java class,可以輕易公有私有的方法，也可以繼承，可以重載等等。因此，在servlet中很容易就可以形成一個全系統追隨的模板，一改一起改。相反，以 ?寫servlet就是在doget中用out.println輸出的，是把寫JSP的理解帶進了servlet;JSP編譯成servlet後，也正是 這個樣子的。所以它不存在繼承的價值。&lt;/p&gt;  &lt;p&gt;那?對于複雜的html界面如何達到與jsp同樣的簡潔嵌入呢？其實很簡單。我當時的解決方案是使用${xxx}標記預置默認的方式，然後把這些帶 有大量html代碼的標記的文件存在某個目錄；在sverlt初始化時通過文件字節流讀入，使用一個字符串分析的組件（今天還在用呢）把標記轉化?相應的 實際動態變量。這恰恰就是今天的號稱最先進的EL 表達式語言的解決方法。真的，我一點都不覺得有寫servlet比一般的網頁程序難在什?地方。某種程度上，我覺得自已做了一個jsp解釋引擎出來了。&lt;/p&gt;  &lt;p&gt;那?這種土?的jsp和真正的jsp有什?區別呢？最大的區別就在于它是把jspp僅僅看成是?servlet服務的html代碼庫，而不是 serlvet?jsp服務。換言之，這?的jsp是類似于今天的tile/Jspfragment的東西。一個小小的差別，帶來的效果完全不一樣，因? 它可以完整的發揮出java面向對象和繼承的特點；甚至可以象PB那樣將整個項目前台作?一個類"繼承"出來，再擴展和重整需要修改的地方。而這種能力， 是那些"P"語言永遠不可能做到的。但是，SUN偏偏跟在微軟屁股後面去拙劣地模仿JSP。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;不妨回顧一下在BS前台最常見到的架構是什?? 是一個大的網站上大部分版面具有類似的框架布局，每個分欄中只有其中某處不一樣。JSP可以很容易地共用其中一樣的部分；但對于其中不一樣的部分就無能? 力。由于JSP不能形成頂級模板，而每一個大分欄中部內容不一樣，所以唯一的辦法就是每一個大分欄拷貝出一個jsp文件來獲得一個頂級框架模板；顯然，這 意味著對每一個文件的相同框架部分進行維護；項目越大，這樣日後更改的工作量越大。這時侯真的有點懷念servlet的功能了，對這種需求，只需要寫好一 個 servlet,其他的servlet繼承它，然後重載它的中央內容方法，就搞惦了。當前要達到類似要求的唯一辦法，似乎只能是在頂級頁面中使用if- else/equal-notequal判斷?include不同的內容文件。舍此，還有什?好辦法嗎？&lt;/p&gt;  &lt;p&gt;JAVA的BS前台的正確的思路應該是以一個可以訂制繼承方法的servlet?核心，然後可以分解一些象jsp這樣的文件，類似今天的jsp中技 術都可以用到這些JSP文件中。也就是說，核心應該是一個可以定制的servlet，而不是提供一個工具，把jsp編譯成不可變的servlet。頂級文 件應該是servlet，而不應該是JSP，這就是我所說的。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;我一個人是不可能與整個JSP社區作對的，不可能一個人完成SUN幾千個開發工程師的工作，既然SUN的某個天才大笨蛋選擇了JSP作? JAVA在 BS的表達主流，到今天，如果我仍使用JAVA作?前台界面程序的話，最好就是隨大流標准，而在幾年前，JSP完全不是標准，情況是不一樣了。不過，從今 天實際的體驗來說，我仍然強烈地覺得，SUN犯了一個嚴重的方法性錯誤。更?遺憾的是，SUN沒有做到的事情，讓微軟在ASP.net中有所體現了，所幸 微軟的東西從來不打算跨平台移植的，所以SUN還有一點機會。&lt;br /&gt; &lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/02/334958.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/02/334958.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/1081807.html"&gt;http://zwwwxy.blogchina.com/1081807.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/03/30/333818.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/03/30/333818.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/blog/article_81038.521777.html"&gt;http://zwwwxy.blogchina.com/blog/article_81038.521777.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/443048.html"&gt;http://zwwwxy.blogchina.com/443048.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://cnjavaxml.blogspot.com/2005/06/jspbs.html"&gt;http://cnjavaxml.blogspot.com/2005/06/jspbs.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/jspservletbsjava_1.htm"&gt;http://javaxml.blog-city.com/jspservletbsjava_1.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871741340938688?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871741340938688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871741340938688' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871741340938688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871741340938688'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/jspservletbsjava.html' title='選擇jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯誤'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871676972688095</id><published>2005-06-13T19:31:00.000-07:00</published><updated>2005-06-13T19:39:29.733-07:00</updated><title type='text'>對《jsp作?BS前台主流方案是方向錯誤 》的歸納性解釋</title><content type='html'>&lt;p&gt;《選擇jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯誤  》已經被不少網友轉載，並有許多反饋意見。現主要就負面的反饋意見的基本面進行一次歸納性的回答。&lt;/p&gt;  &lt;p&gt;《選擇jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯誤  》一文是經驗角度對jsp選擇方向的一種質疑；其不受"公論"（公論對中國人的思維影響很大）的逆向思維方式本身就會引起爭論，本是意料中的。現把部分爭論回答歸納起來，學習、實踐、爭論、歸納、再實踐，這是取得提高和突破的途徑。&lt;/p&gt;  &lt;p&gt;首先，JSP是一種WEB界面處理方式（不是語言），所以是否適用MCV模式實際在存在著很大的爭議。所以MCV模式作?JSP/SERVLET的 選擇依據是不合適的。不過，JSP/SERVLET的表達層的應用方式，是沒有疑問的，盡可能將業務邏輯層分離出去，符合項目需求控制和成本控制的原則， 最終將提高項目質量並降低維護成本。無論是那一種方案，將應用業務邏輯包裝起來，成?與其他模塊/層盡可能低耦合的類，也是一種必然的選擇，也是面向對象 的方式的體現；面向對象方式主要體現?繼承/接口，如果否認它的積極意義，也就沒有討論的余地了。&lt;/p&gt;  &lt;p&gt;OOP誰都會接受的，但這?關鍵焦點在于，對象是什?？在不同的環境，對象有完全不同的含義，脫離這點，OOP其實成了一個過分泛濫的無用的名詞。 在VB中它通常表示界面中的一個視窗組件；而在C++中，通常是處理的一組功能；在JAVA中的業務邏輯中，對象一般是有獨立意義的一種客觀事物，而當 JAVA用于表達層時，無論是JSP/還是swing.awt，它都象VB一樣表達一種view圖結構。到底表達什?，什?可以抽象，什?應該抽象，很大 程度取決于開發者的經驗習慣。&lt;/p&gt;  &lt;p&gt;JSP中適用那種類型，首先要回憶JSP針對的開發模式/假想是什?，也就是JSP這種技術?品出現時的分析用例是什?。文中其實已經提到了最根本 的論點和解釋（居然有網友沒有讀出來），JSP用例是抄ASP的，也就是"希望非程序人員可以直接生成動態內容"的JSP，這是SUN選擇向JSP進化的 最根本的理由。文中最大的論據也在于：事實表明非程序人員寫不了JSP；所以JSP側重點本身就錯了，它應該選擇方便程序員的方向!&lt;/p&gt;  &lt;p&gt;再回想一下各人接手的項目是什?形式的。或者是從個人開始，按客戶要求（甚至自已就是客戶？）直接開發系統；開發一個版反饋給客戶再修改第二版？還 是接手一批原型，一般是HTML，然後從這?著手抽象可以抽象的東西，包裝可以包裝的東西？即使是第一種情況，開發者包打天下，最經常的方式是什?呢？應 該是萬般抄開始，從網上找相近的網頁，變成HTML後修改。可見，可以把WEB的開發看作是從HTML開始的。問題的差別就在于是如何從HTML開始的。&lt;/p&gt;  &lt;p&gt;如果認?是從HTML直接開始，從中通過插入各種生成值，也就是SUN最早假設的方式；最終生成簡單的網頁，當功能不太OK  時再一頁頁延伸，那?JSP的確是合適的選擇。順便說一句，如果生成的是邏輯功能簡單而頁面表達複雜的HTML，（這是中國式網站的最典型情況），JSP  的優越性是非常明顯的。不過反過來，這樣的缺點也就在于隨著項目的開展、龐大、複雜化，開發者和維護者最終都會陷入"網頁陷阱"，也就是頁面變程序缺乏邏輯的聯系，變得難以維護了，這其實也是?什?要用動態網頁代替HTML的原因。&lt;/p&gt;  &lt;p&gt;更通常的做法是在HTML上再處理，抽取出各個特征代碼，一一包裝起來成?可重用的組件，（注意和業務邏輯組件的區別），另一方面，組件中的 HTML代碼?了修改方便，要求修改後是無需編譯的。從這個要求出發，派生出了XML/XSL/XSLT一整個體系，也派生出了TILES，SLIDE， struts包括它的validator,等等。無論是那一種，HTML必須整理再分解才有可能達到重用和降低維護成本的目的。對于功能/內容/服務驅動 的網站，網頁一般簡潔並功能模塊重用性高，這種操作方式尤其顯得高效而簡潔，網頁本身就可以直接用UML/USECASE的方式預先設計。這就是《選擇 jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯誤 》中假設的項目類型，也就是這時侯，對象的繼承對于表達層才有現實的意義。&lt;/p&gt;  &lt;p&gt;事實上，JSP也是基本支持上面的網頁分解、抽象、重用，最經常是使用include方式；在taglib和struts:logic中，還可以根 據上下文變量條件決定include，所以也基本上達到了類似的目的。《選擇jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯 誤》一文爭論的是，是JSP不能處理重用頂級模板，限制了這種表達層對象抽象重用的水平。如果選用servlet?主要方向，同樣的投入，要達到方便程序 員直接修改界面代碼，同時也便于（選擇）各個方向層次的對象應用，就沒有JSP那樣的障礙的。SUN在開始JSP時是一個無負擔的開發者，完全可以這樣 做，但卻選擇了與ASP雷同的用例方案，沒有利用自已最大威力的對象語言，把JAVA降格成腳本（javalet），最終不得不通過開發標簽 /javabean來彌補原來的不足，不但加大了學習者的負擔（就以Tag而論，能熟練使用的jsp程序員有幾何？），也減少了自已的市場份額和市場成功 的機會。這就是對《選擇jsp而不是servlet作?BS前台主流方案是JAVA的戰略性方向錯誤 》批評SUN是笨蛋的原因。&lt;/p&gt;  &lt;p&gt;無論如何，IT/軟件行業，是一個支持獨立思考，支持創造性思維的行業，可以懷疑一切權威，在實踐中體驗並用實踐來證明，是軟件行業技術進步的基 礎，也是IT行業存在的基礎。這不是一個子日詩雲，權威（老師）定論的領域，如果否認這一點，象一些人表現的那樣對權威的奴性崇拜，也就沒有什?再討論的 必要性了。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/02/334958.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/02/334958.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/1081807.html"&gt;http://zwwwxy.blogchina.com/1081807.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/03/30/333818.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/03/30/333818.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/blog/article_81038.521777.html"&gt;http://zwwwxy.blogchina.com/blog/article_81038.521777.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/443048.html"&gt;http://zwwwxy.blogchina.com/443048.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871676972688095?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871676972688095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871676972688095' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871676972688095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871676972688095'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/jspbs.html' title='對《jsp作?BS前台主流方案是方向錯誤 》的歸納性解釋'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871590760563907</id><published>2005-06-13T19:17:00.000-07:00</published><updated>2005-06-13T19:25:07.613-07:00</updated><title type='text'>使用ConnectionManager適應多數據庫的應用環境</title><content type='html'>&lt;p&gt;今天企業應用環境中一般情況下要面對不止一個或一類數據庫；另一方面不同時期的不同種類的數據庫形成一個個的荒島；在java中，技術潮流傾向于不 是直接操作數據庫記錄，而是通過中間層的數據庫對象持久化處理達到OO的目的。無論那一種，都要求比較容易地面對多個數據庫連接。多個數據庫連接比較?人 所熟悉的是微軟的ODBC數據源設置，除了沒有實現中間層持久化外，ODBC其實比JDBC要全面也更容易處理。ConnectionManager是一 個通過 XML設置的，類似于ODBC數據源設置的東西，通過定義dao.Connection對象，程序可以按需要以:&lt;br /&gt;java.sql.Connection  conn    =ConnectionManager.getConnection(${connectionname});&lt;br /&gt;得到所需要的連接，從而簡化了在多個數據庫環境下的編輯工作。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;    現在項目開發者面臨的常常是多個數據庫的應用，曆史的和不同部門的，有CS後台的也有BS前台的。各個數據庫的數據必須融彙到同一個業務邏輯中，否則就成 ?一個個低價值的數據孤島。應對這種需求，目前使用了兩種技術，一是數據對象化技術，實質就是在數據層和應用邏輯層中間插入一個持久對象化層，通過程序或 容器使數據對象與數據記錄相一致，而應用邏輯直接訪問數據對象而不是數據庫記錄；二是通過使用全局目錄調動使用多個數據庫供數據對象化管理層使用。無論是 EJB ENTITy,還是Hibernate，抑或是我處已寫的Hanva Processor都是這種思路的一種體現。&lt;/p&gt;  &lt;p&gt;    並不總是需要采用EJB才能管理多個數據源，何況大部分項目中采用EJB帶的是更高的成本和性能的更低效，開發工作更複雜化，甚至只是碰運氣地填代碼再發 布不行再填代碼再碰運氣，（我本人很討厭這種開發感覺，所以搞了一個Hanva的小項目，除非客戶指定EJB了）。不過EJB容器中管理多個數據源的方式 還是很值得學習的。大部分情況下，它是通過初始化後的數據源對象，象連接池，注冊進JNDI SPI;然後通過java.naming.Context.lookup()這個全局名稱（在JVM範圍內）。我的做法是由寫一個 ConnectionManager，它由一個xml文件定義多個數據庫連接相關的參數，在ConnectionManager初始化時讀入內存。使用時 然後通過調用ConnectionManager的靜態方法getConnection （String connectionname），就可以得到指定數據庫連接。由于實際上操作數據庫連接的都是Processor和Lister兩個類，這樣，要保證連接 資源的釋放也是很有把握的。依靠這個方法，就可以在輕型的應用中都可以搞妥多數據庫，使用數據對象化方式進行開發了。&lt;/p&gt;  &lt;p&gt;connections.xml定義:&lt;/p&gt;  &lt;p&gt;&lt;connection-set&gt;&lt;br /&gt;&lt;description&gt;&lt;![CDATA[&lt;br /&gt; connection-set供ConnectionManager使用，可以按需要取用不定的多個連接定義，代碼完全不變。從而適應多數據庫的使用環境；&lt;br /&gt;]]&gt;&lt;/description&gt;&lt;br /&gt; &lt;connection name="GlobalPool" driver="datasource" uri="java:comp/env/globalpool"&gt;&lt;br /&gt; &lt;connection name="MysqlPool" driver="datasource" uri="java:comp/env/mysqlpool"&gt;&lt;br /&gt; &lt;connection name="mysql" driver="com.mysql.jdbc.Driver" username="michelle" password="favordog"&gt;&lt;br /&gt;   &lt;uri&gt;&lt;![CDATA[jdbc:mysql://127.0.0.1:3306/dkt?useUnicode=true&amp;characterEncoding=gb2312]]&gt;&lt;/uri&gt;&lt;br /&gt; &lt;/connection&gt; &lt;br /&gt; &lt;connection name="conn" driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;   uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="dcon"  password="girlfriend" /&gt;&lt;br /&gt; &lt;connection name="reso"  driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;   uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="erso" password="abc"  /&gt;&lt;br /&gt; &lt;connection name="daifu" driver="oracle.jdbc.driver.OracleDriver" &lt;br /&gt;  uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="eef"  password="qwewer" /&gt;&lt;br /&gt; &lt;connection name="system"  driver="oracle.jdbc.driver.OracleDriver"&lt;br /&gt;   uri="jdbc:oracle:thin:@127.0.0.1:1521:dkt0" username="system" password="manager"  /&gt;&lt;br /&gt;&lt;/connection-set&gt;&lt;/p&gt;  &lt;p&gt;ConnectionManager方法：&lt;/p&gt;  &lt;p&gt;public class ConnectionManager{&lt;br /&gt;  private static LOGGER logger  =(LOGGER)Loger.getLogger(Constants.LOGGER_DAIFU_KEY);&lt;/p&gt;  &lt;p&gt;public static synchronized java.sql.Connection getConnection() throws  java.sql.SQLException{&lt;br /&gt; String name  =Repository.getInstance().getConn();&lt;br /&gt; return getConnection(name);&lt;br /&gt; }&lt;/p&gt;  &lt;p&gt;public static synchronized java.sql.Connection getConnection(String name)  throws java.sql.SQLException{&lt;br /&gt; if(Repository.getInstance()==null){&lt;br /&gt;   logger.error("the repository for dao operation has not been initialized");&lt;br /&gt;   return null;&lt;br /&gt;  }&lt;br /&gt; dao.Connection conn  =Repository.getInstance().getConnection(name);&lt;br /&gt; String dri  =conn.getDriver();&lt;br /&gt; java.sql.Connection cn =null;&lt;br /&gt; try{&lt;br /&gt;   if(dri.equalsIgnoreCase("datasource")){&lt;br /&gt;   javax.naming.Context initCtx = new  javax.naming.InitialContext();&lt;br /&gt;   javax.sql.DataSource ds =  (javax.sql.DataSource)initCtx.lookup(conn.getUri());&lt;br /&gt;          cn        =  ds.getConnection();&lt;br /&gt;   }&lt;br /&gt;  else{&lt;br /&gt;   Class.forName(dri);//no  newInstance();only get class&lt;br /&gt;                 cn =  java.sql.DriverManager.getConnection(conn.getUri(),conn.getUsername(),conn.getPassword());&lt;br /&gt;    } &lt;br /&gt; }catch(Exception ex){&lt;br /&gt;  String msg  ="ConnectionManager.class,conname:="+name+";dri:="+dri+";cn:="+cn+";msg:="+ex.getMessage();&lt;br /&gt;   logger.error(msg,ConnectionManager.class);&lt;br /&gt;  throw new  java.sql.SQLException(msg);&lt;br /&gt;  }&lt;br /&gt; return cn;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;public static  synchronized java.sql.Connection getConnection(dao.Connection conn) throws  java.sql.SQLException{&lt;br /&gt; if(conn==null){&lt;br /&gt;  System.out.println("the  dao.Connection to getConnection is null;");&lt;br /&gt;  return null;&lt;br /&gt;  }&lt;br /&gt; String  dri =conn.getDriver();&lt;br /&gt; java.sql.Connection cn =null;&lt;br /&gt; try{&lt;br /&gt;   if(dri.equalsIgnoreCase("datasource")){&lt;br /&gt;   javax.naming.Context initCtx = new  javax.naming.InitialContext();&lt;br /&gt;   javax.sql.DataSource ds =  (javax.sql.DataSource)initCtx.lookup(conn.getUri());&lt;br /&gt;          cn        =  ds.getConnection();&lt;br /&gt;   }&lt;br /&gt;  else{&lt;br /&gt;   Class.forName(dri);//no  newInstance();only get class&lt;br /&gt;                 cn =  java.sql.DriverManager.getConnection(conn.getUri(),conn.getUsername(),conn.getPassword());&lt;br /&gt;    } &lt;br /&gt; }catch(Exception ex){&lt;br /&gt;  String msg  ="dri:="+dri+";cn:="+cn+";msg:="+ex.getMessage();&lt;br /&gt;   logger.error(msg,ConnectionManager.class);&lt;br /&gt;  throw new  java.sql.SQLException(msg);&lt;br /&gt;  }&lt;br /&gt; return cn;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;public static  void main(String[] args) throws Exception{&lt;br /&gt; if(args==null ||  args.length&lt;2){&lt;br /&gt;  System.out.println(" Please input the xml and conn's  name");&lt;br /&gt;  return;&lt;br /&gt;   }&lt;br /&gt; Repository.parse(args[0]);&lt;br /&gt;&lt;br /&gt; java.sql.Connection conn  =getConnection(args[1]);&lt;br /&gt; System.out.println(conn);&lt;br /&gt; }&lt;/p&gt;  &lt;p&gt;}&lt;/p&gt;  &lt;p&gt;調用時只需要&lt;/p&gt;  &lt;p&gt;java.sql.Connection conn =ConnectionManager.getConnection("connn");&lt;/p&gt;  &lt;p&gt;就可以得到指定方式的數據庫連接。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/01/334718.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/01/334718.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/808527.html"&gt;http://zwwwxy.blogchina.com/808527.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/connectionmanager.htm"&gt;http://javaxml.blog-city.com/connectionmanager.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871590760563907?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871590760563907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871590760563907' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871590760563907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871590760563907'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/connectionmanager.html' title='使用ConnectionManager適應多數據庫的應用環境'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871542694850699</id><published>2005-06-13T19:09:00.000-07:00</published><updated>2005-06-13T19:17:06.953-07:00</updated><title type='text'>優化apache/tomcat配置</title><content type='html'>&lt;p&gt;有充分證據表明現得絕大多數的apache/tomcat配置中,apache根本就是擺設，所有的響應負擔，包括靜態多媒體文件實際上是由tomcat  完成，而tomcat實際上是效率相當低的，大約是apache的十分之一。因此，沒有達到集成兩者的目的；但在優化配置本地基本成功，打算在網上測試服務器實際試行時，卻碰到了"martix現象"：無可解釋的不可重複的異常表現。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;看來，在tomcat/apache的配合上要動真格的，今天寫的那份文章提示了一個現實的問題，apache根本就沒有作用，更嚴重的 是，107 和106上不匹配，107上甚至不能重複出106的配合。由于圖片的量會不少，所以這是一個非常現實的問題。我想，目前唯一的辦法就是下載到本地，參考可 能參考的資料完整地進行一次配置。畢竟，現在的配置是幾年前的，而且不是由我進行的。這?如果處理OK了，那?相信對于提供系統的處理能力和處理的速度， 是大有益處的。......經過一天的奮鬥，主要的時間在于重新在本地設備上安裝所有相關的軟件，包括本地的DNS服務器，沒有這個沒有辦法測試虛擬主機 解釋。所以主要還是在晚上測試，深入鑽研apache/tomcat的配合，基本搞清楚了兩者的關系，確認原來的配置方式只是"表面上成功"，實際上完全 由 tomcat完成所有應答，apache只是聾子的耳朵——擺設。但是在本地完成所有測試，原封不動地准備在網上進行更新設置時，再次碰到"Matrix 現象"：出現了莫名其妙的差異；無法解釋，自然消失。&lt;/p&gt;  &lt;p&gt;第一個差異就是，按照最新的理解，apache解釋的多媒體路徑與tomcat解釋的頁面路徑是不同的，因此，必須在頁面上修整兩者，否則圖片和多 媒體就會因?路徑不一而不能獲取；而在原來設置中由于完全由tomcat解釋，所以兩者是相同的。這個設想的實驗在本地非常成功，但是在網上，就完全相 反，路徑解釋無論如何都是對的——問題在于我在本地已經測試並修改了這個路徑解釋：老天爺，到底要那一個呢？而實際上， worker.properties的過濾是完全一樣的。這點如果還不算太怪的話，那?第二個差異就更怪了。&lt;/p&gt;  &lt;p&gt;首先是使用原來的httpd.conf總是在虛擬主機DocumentRoot上被禁止訪問，在強行使用本地設置文件置換（由于路徑一樣，問題倒不 算大）後就變得可以了。這條權作是未知的某處錯誤存在，那?隨後就怪事連連了：無論是那個虛擬主機，統統只是解釋到第一個虛擬主機的目錄，換言之，虛擬主 機完，全失效。把那個設置文件拿回本地測試卻是一切正常。隨後再次到網上測試，這次卻是跟著正常了......原因不明，唯一的可能......似乎是 firefox緩存一類......總之是筆糊塗帳。真是莫名其妙。但前者的圖片必須改由apache解釋是確證無疑的，否則，系統性能會過大消耗，靜態 大文件的處理，不是tomcat的長處。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;我們這個世界是一個物質物理世界，它的基本特征就是同質可重複性，整個現代科學都是建築在這個基礎上的。如果一旦碰到同質可重複性不能成立時，我的感覺就是俺是不是生活在Matrix?頭了。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;續：&lt;br /&gt;今天在本地的測試得到了與遠端同樣的結果，至少看來重新象一個物質世界了！  目前唯一可能的解釋，（不過也是解釋得非常牽強的），就是firefox對于?覽過的網站或者出于加速的原因，有一些與過往的?覽器有很大不同的緩存策略。在以後的操作中要注意這一點。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;      這個結構許多人已經熟悉用了，而且在網上也有大量的howto，不過最關鍵的文件 worker.properties設置就未必正確，如：  &lt;/p&gt;  &lt;p&gt;info=Ajp13 forwarding over  socket&lt;br /&gt;tomcatId=localhost:8009&lt;br /&gt;[uri:/jsp-examples/*]&lt;br /&gt;[shm:]&lt;br /&gt;disabled=1&lt;/p&gt;  &lt;p&gt;如果象上面那樣uri:/jsp-examples/*的話，相信，apache屁用沒有，根本上就是tomcat承受了一切的負擔。  顯然，如果是這樣配置，系統承受的負擔,我指的是java  服務器，將是大大超出應有的負荷的。應該修改上面的配置，讓apache承但，主要是html和圖片以及多媒體的下載任務，而不是tomcat,估計可以大大提供這個搭配系統的負載能力。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;......&lt;br /&gt;前天寫到這?，忽然覺得這個配置頗?眼熟，趕快去查一下，果然現在的項目中的設置就是這個樣子的，但是進一步的測試就 讓我有點入歧途，一會兒證明是那樣，一會兒就表明是那樣。軟件這東西如果缺乏邏輯必然的聯系，人是沒有什?好幹的。無論如何，繼續上面的思路，象上面的配 置，表明所有/jsp- examples/*次級目錄下的東東都是交由tomcat處理；Apache並沒有相應的工作。正確的配置應該是：&lt;br /&gt;[uri:/jsp-examples/*.jsp]&lt;br /&gt;[uri:/jsp-examples/servlet/*]&lt;/p&gt;  &lt;p&gt;如果使用了如struts，大概還需要增加*.action這樣的後綴。這樣，非此類型的文件將會交給apache。而這樣的設置：&lt;br /&gt;[uri:/*] &lt;br /&gt;有極大的危險，將意味著所有的請求全部由tomcat響應；不過，看來ajp13作了預防性措施，事實上，這時侯ajp13把所有請求扔進了下水 道，什?也不幹。負作用就是虛擬主機的根目錄我無論如何設不出它能夠直接識別index.jsp引導。只能使用html代替，不過，這也沒有什?大不了 的，如果是小型的首頁，可以就地轉向，而假如是大型的首頁，本身就會定時轉換輸出?html頁面。顯然，在這種結構中使用通配符是最容易配出運行框架的， 卻也是錯誤的。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;    把Apache與tomcat合並起來後，還得到了一個意外的收獲，就是可以使用連接形式把一些主要的非jsp/servlet文件由apache在目錄 以外解釋，從而簡化了開發目錄的管理。在實際的開發過程中，如果規劃不佳，不多久就會積累了大量的無用的圖片文件，工作目錄動不動超過一個G是非常正常 的；如果開放部分如允許用戶上載文件之類，更是大得驚人，但是由于tomcat不能解釋symbolic鏈接，這樣就不能把這些圖片移到目錄以外，只能是 使用全url才有可能實現，而把在合理配置 Apache/tomcat後，盡管tomcat不能解釋鏈接符號，但Apache能夠，這樣，就把上面的問題解決了。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/11/343533.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/11/343533.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/676895.html"&gt;http://zwwwxy.blogchina.com/676895.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/apachetomcat.htm"&gt;http://javaxml.blog-city.com/apachetomcat.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871542694850699?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871542694850699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871542694850699' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871542694850699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871542694850699'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/apachetomcat.html' title='優化apache/tomcat配置'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871497210221137</id><published>2005-06-13T19:00:00.000-07:00</published><updated>2005-06-13T19:09:32.110-07:00</updated><title type='text'>使用jsp完成文件可定制上載</title><content type='html'>&lt;p&gt;    這幾天的工作主要圍繞著文件（主要是圖片）上載，並可以在線和HTML編輯器集成，操作簡便與目前引用網上圖片相似。我是有點小看了這件事情，不過也不無 道理：一來以前使用servlet完成過，其中的核心DoUpLoadBean也的確是可以工作；其次集成到編輯器則在使用php的本人的私人博客上做 過，看不出有什?特別難的地方。但實際上在展開後就發現，簡單實現上載是容易的，但要合理地安排上載的策略，就不得不小心翼翼。因?允許上載本身是非常需 要危險的，這實際上是開了一個口子；允許客戶對服務器進行事實上的操作，上載攻擊從來就不是一件困難，更不是一件罕見的事情；可以想見一旦系統開通，這類 攻擊必然就會發生。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;    另一方面，在允許用戶上載本地文件同時就必須考慮後期的管理，因?，即使是在用戶本地，最大的硬盤也會過不多久就會給說不清是什?東西的垃圾占滿；何況現 在是允許許多人同時使用的服務器，如果沒有精確的策略，花不了多長時間，客戶的上載文件就會把系統撐爆。就在上一個星期，一位朋友向我求助，說是他們的數 據庫達到30G，把硬盤吃光了，結果死了機；對此，本人只能是愛莫能助，因?，可以肯定?面絕大部分是垃圾，卻搞不清什?是垃圾，什?是必須的。因?，他 們缺乏一個策略。而且，就算用戶不是惡意的，大部分情況下，在開通開載的時侯，很快硬盤也會撐滿，如果這是系統盤，通常就意味著崩潰，可見，必須使用連接 把上載限制到另一個專用的分區，以確保安全。通常鐵quota在這?是派不上用場的，因?那需要把WEB帳號與操作系統帳號結合，既複雜又危險，更加沒有 這個必要。同時，上載的文件如果不是給每個用戶分配目錄，也應該是在每個用戶的名稱前增加一個前綴，以供識別；這樣，萬一需要清理，配合文件日期，可以使 用find/grep/rm組合腳本進行備份或清除，至少是有可能的。&lt;br /&gt;      還有其他因素，導致上載文件實際操作比簡單接愛一個文件上載的程序量要大得多；其中主要包括權限控制，（考慮到可以用上載進行攻擊，這條不得不小心點）， 文件管理，以及修改屬性，包括大小，類型限制，可以方便修改存儲的方式等等，事實上，就完成情況下，上載部分只花了五行程序，而管理則不小于50行。&lt;br /&gt;      今天已經不必再自已寫輸入流了，就算自已沒有積累，還是可以從網上找到開源的代碼，象jakarta commons upload就是一個。這個東西沒有什?例子，所找到的例子大部分是跑不動的，倒不是怪程序員自已，而是這個東西不但沒有什?文檔，還把方法和類也改了： 例子說的UpLoad實際上是DiskUpload,而當前的Upload有什?區別，?什?可以省去設置內存耗量的等部分，我找不到任何的解釋。雖然對 自已的代碼有所偏愛，但由于我的代碼不能處理多個file上載,雖然，這種情況實際上也很少，我卻一直弄不明白有什?辦法可以識別不止一個上載請求，這意 味著我對RFC1864仍是欠了解的，既然有更可靠的東東，就不要太偏心自已的東西了，結果把用了幾年的DoUploadBean徹底地埋葬了。&lt;br /&gt;        在選擇是使用jsp還是servlet處理上載時，顯然兩者中servlet更規範一點，但在權限控制上頗?不便，因?，所以識別變量必須通過  request獲取，這也意味著存在客戶端?造變量直接提交上載的可能性，確保正確識別意味著大量的代碼。我最終決定采用自已發明的使用jsp標簽取代  servlet的辦法，（參看《可以使用多個jsp標簽達到類似servlet效果》一文）。結果表明，這的確是兼有  jsp/servlet/javabean優點的好辦法，特別是修改非常容易，我改個主意要以用戶名稱開目錄，只是改了標簽一個定義屬性就搞妥了，這才真是易用性的體現。&lt;/p&gt;  &lt;p&gt;最終的使用方法很簡單：&lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt;這樣，saveupload標簽就會自動檢測權限，並按科室中定義的管理組允許其中的成員上載，上載到科室下的upload目錄中的用戶名稱建立的專用目錄中，而存盤的文件名使用theimg名稱供客戶端嵌進正在編輯的文本中。&lt;/p&gt;  &lt;p&gt;這樣，上載就真正成?一個可以自由方便地使用的組件了。&lt;/p&gt;  &lt;p&gt; &lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/04/11/343545.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/04/11/343545.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/672335.html"&gt;http://zwwwxy.blogchina.com/672335.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/jsp.htm"&gt;http://javaxml.blog-city.com/jsp.htm&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;p&gt;&lt;br /&gt; &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871497210221137?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871497210221137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871497210221137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871497210221137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871497210221137'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/jsp.html' title='使用jsp完成文件可定制上載'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871439818992082</id><published>2005-06-13T18:51:00.000-07:00</published><updated>2005-06-13T18:59:58.193-07:00</updated><title type='text'>可以使用多個jsp定制標簽在JSP中達到接近servelt的處理效果</title><content type='html'>&lt;p&gt;    jsp可以令菜鳥直接寫簡單的網頁程序（網友言），而servlet卻有jsp所不及的集成程度和易維護性。兩者在JAVA/BS系統中無法簡單取代，但 同時並存卻令開發者陷入近兩年來最常見的陷阱中：必須在一個即使是相對簡單的項目中維持多套程序模式的方案，顯然，這是高成本的。本文考慮並初步實驗了使 用標簽組件連續完成類似servlet的處理效果，從而達到魚和熊掌兼得的目的，看來有一定的效果。&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;    在完全使用servlet的環境中，可以使用servlet的繼承獲得上級servlet的設定屬性；還可以使用servlet-chains達到分類處 理的目的，整個WEB程序與實際應用系統非常相似，高效而簡潔；在servlet-jsp的環境中servlet起到集中處理請求的作用，而jsp負責顯 示各種形式采摘的數據。後者最麻煩的就是在servlet/jsp中的數徑和變量處理方式不一致，平添大量的原始的工作量。strutsr actionmapping一定程度上解決這個問題，不過解決得不算太徹底。因此在大型的java BS應用中采用servlet/jsp形式所帶來的方便，一定程度上將會被這種變量的不一致性所抵消，畢竟，維持兩種處理方案本身就是高成本的。&lt;/p&gt;  &lt;p&gt;    因?這個原因，過去本人幹脆完全采用servlet形式，而通過另外寫程序解釋由網頁人員編寫的嵌套式的html來達到與JSP類似的目的。這套方案在三 四年前是有效的，但在今天由于SUN選擇了JSP作?發展的主體，包括JTL，TAG技術，甚至于jsdk1。5中的cacheResutlSet都是? 了這種（我認?是落後的）JSP隨機編碼而開發，因此，獨自堅持走servlet道路是不明智的,(參看本人《選擇JSP作?BS發展方向很可能是致命的 戰略失誤》一文)；但是，同樣的疑問並不會因?SUN選擇了JSP而消失：如果完全采用JSP，那?在數據提交處理上還是必須使用SERVLET以簡化處 理邏輯，但同時也必須承受上述的負面作用。&lt;/p&gt;  &lt;p&gt;    作?SUN贊助支持的JAVA/BS主體項目方案之一的struts框架充分體現了這一矛盾帶來的困惑和折衷：struts-  action/actionmapping本身就是?了達到克服上述的JSP不足，希望魚和熊掌兼得，通過ActionServlet令使用者減少  servelt程序的編寫量；不過，在不能完全解決問題的同時，也令開發者?了這不是主體需求的需求，而必須多采用一個框架；一定程度上實際上是得不嘗失。&lt;/p&gt;  &lt;p&gt;    如果上述邏輯成立，那?如同幾年前本人完全選擇servlet一樣，既然選擇了jsp作?主體方案，那?就應該考慮完全?棄servelt，以便以一套方 案處理項目，避免維護兩套系統帶來的附加性成本。但是如同所有人在若幹年前指出的一樣，JSP缺乏有效的代碼管理手段；也不便于形成象servlet那樣 的基本框架體系，這樣它與簡單的網頁程序如ASP/PHP沒有什?不一樣。引入javabean(組件，不是簡單的數據對象化載體），可以一定程度上改善 這種處境，但javabean缺乏統一的調用規範，卻令這樣的JSP比純粹的servelt開發顯得更?麻煩。&lt;/p&gt;  &lt;p&gt;    我在使用tag時，覺得可以吸取servelt-chains的概念，使用象SimpleTabSupport這樣最簡單的標簽方式，生成一個個的命令形 式的標簽，參數可以直接作?標簽參數輸入，這樣在某個jsp中次第引入這種標簽命令，就可以達到類似于servlet-chains的效果，而從易于配置 使用上看，超過了servelt。?簡便起見，我以struts的ActionServlet?藍本，寫成一個ActionTag的基本類，同樣使用 ActionErrors/ActionForm作?數據和消息的載體；然後所有的Command標簽全部繼承這個ActionTag，這樣編寫一個命令 標簽的工作量不會比編寫一個struts-action bean的工作量更大。另一方面，由于標簽直接可以接受參數設定，所以無需任何如Actionmappin這樣的預設置，實際上簡化了維護。我認?僅此而 言，它至少比struts的ActionMapping要簡潔有效。&lt;/p&gt;  &lt;p&gt;    類似這樣的在一個平面上以標簽形式執行多個命令的處理方法並不鮮見，大名昭昭的Apache的httpd.conf就是使用這樣的方式完成設置的。&lt;/p&gt;  &lt;p&gt;     通過這樣的方法，可以統一以JSP的方式來處理幾乎所有BS的網頁請求，接受在JSP頁面上的目錄和變量的同樣設定，估計可以大幅度降低開發和維護的成本，以及降低相應的技術要求。&lt;/p&gt;  &lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/603990.html"&gt;http://zwwwxy.blogchina.com/603990.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://javaxml.blog-city.com/jspjspservelt.htm"&gt;http://javaxml.blog-city.com/jspjspservelt.htm&lt;/a&gt;&lt;br /&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871439818992082?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871439818992082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871439818992082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871439818992082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871439818992082'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/jspjspservelt.html' title='可以使用多個jsp定制標簽在JSP中達到接近servelt的處理效果'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871387081568230</id><published>2005-06-13T18:47:00.000-07:00</published><updated>2005-06-13T18:51:10.820-07:00</updated><title type='text'>最終還是手工輸出XML對象可靠</title><content type='html'>和xml打交道，常常是哭笑不得：我?什?要花那?大力氣和整個XML文檔打交通呢？實實在在的，我只不過想存取其中一個對象的屬性罷了！！前段時間了解 了castor覺得這是一個解決方案，不過也還是需要整個文檔的讀寫更新。一來是時間限制不允許當前深入研究，而且那也是一個不算成熟的項目；二來呢，采 納的話會和現在的digester讀取模式發生沖突，有點劃不過來。但是象科室設置的更新頻率看來越來越高，再放到XML中只讀靠手工改看來是不行的。因 此打算把科室對象移植進數據庫，但一動手就發現同樣有不劃算的地方。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    事實上是發現忽視了一個問題，其實也是XML和關系數據庫存儲實質的一個對比內容：XML周邊存取的手段的確不是非常成熟，但是它是以對象的層次結構存儲 數據的，而關系數據庫則是平面形式地存儲。我目前打算使用secion轉?關系數據庫，目的是?了可以分科室的更改設置更方便，這在XML是一個文件，而 到了關系數據庫，卻是整個的一堆的關系表（關系概念中同樣是一個實體，但此實體非彼實體，它意味著反應一個對象的一堆表），而且要與象表類等進行關聯，相 當複雜的。當前這也許不是一個好主意，而且，在大項目中使用複雜的關系結構表達數量不多的記錄，似乎是一種成本效益比很低的過時的方法。所以，我猶豫了。&lt;br /&gt;&lt;br /&gt;另一個辦法是做一個可更新的xml模件：處理手法包括：&lt;br /&gt;&lt;br /&gt;1、修改SectionBase，使它是針對多個科室的多個xml工作，而不是象現在那樣一切解釋把所有的科室讀進去；&lt;br /&gt;&lt;br /&gt;2、做一個更新各個科室的xml的方法；無論是casto的，還是其他什?方法的；&lt;br /&gt;&lt;br /&gt;3、做一個更新各個科室的界面，把它連到科室管理台。&lt;br /&gt;&lt;br /&gt;這?的關鍵是第二步。?確認第二步能夠以當前最簡單的方法完成，再次翻看先前下載的關于castor的文章，不過博客中國真是越來越弱不禁風，居然好久還 動不了，過好長時間才把原來的文章打開再讀一篇。研讀結果仍是一樣的，如果采用castor就意味著要采用它的JDO，而不僅僅是XML的輸出，而目前我 的讀入主要是使用digester；所以這?包含著更大範圍的修改，而且包含著更大不定性的試用；這也是我上兩個星期暫時放開castor的原因：目前沒 有時間深入研究它的使用思想和實際應用。看來，只能采用原始點的SAX或甚至字符串處理了。&lt;br /&gt;&lt;br /&gt;再考慮一下常用的sax/xalan/jaxp/jdom幾種處理手法，如果不是單純對著非對象化的文檔內容工作，就是需要寫一個XSLT/和轉換器，而 無論如何，要與一貫的JAVA對象/XML對象匹配的模式一起工作，還必須做到讓上面的這些文檔對象可以與digester後的JAVA對象互換的方法： 沒聽說過！！從digester都沒有幾個人真的用過的情況下，我看就算上論壇問那幾個國內國外的老兄都是白問。我想這種方法如果有，一定就在 Digester的具體使用中，從jdom中獲得對象，以及重新轉?document對象——不過，沒有！！&lt;br /&gt;&lt;br /&gt;看來，我要考慮一下自已實現的難道和可重用性是怎?樣的。......一想下來，其實這也不是什?難事，只需要在每個類那?實現一個接口，比如說 write，然後逐級調用不就搞惦了?？何必舍近求遠，找些不可靠的東西試用呢？一通百通，實際上手工輸出對象字符串一點都不是一件恐怖的事，我是讓那些 文章作者給唬住了，關鍵就在于這是按對象輸出，程序量並不算大，而且也是挺好管理的。相比寫servlet輸出，小意思啦。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;原始的方法不見得就是落後的，合適就行！&lt;br /&gt;&lt;p&gt;&lt;a href="http://zwwwxy.blogchina.com/501600.html"&gt;http://zwwwxy.blogchina.com/501600.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/03/30/333829.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/03/30/333829.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/xml.htm"&gt;http://javaxml.blog-city.com/xml.htm&lt;br /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871387081568230?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871387081568230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871387081568230' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871387081568230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871387081568230'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/xml.html' title='最終還是手工輸出XML對象可靠'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871251569815939</id><published>2005-06-13T18:24:00.000-07:00</published><updated>2005-06-13T18:28:35.706-07:00</updated><title type='text'>在Unix/Linux上令(java)JVM支持中文輸出</title><content type='html'>一、在Unix/Linux上令JVM支持中文輸出&lt;br /&gt;&lt;br /&gt;如果用戶使用的是UNIX的遠程服務器，就會遇到中文字體在圖像中輸出的問題，特別是由于許多管理員並不喜歡把主機的locale定?zh(因?意味著可 能出亂碼或必須裝微形圖形終端象zhcon，但很多情況下這樣的條件並不具備)。大部分程序員的JAVA經驗苟限于JSP腳本程序，部分熟練的程序員大概 開發過中間件、servlet、applet或在WINDOWS上運行的GUI程序。如果開發的jfreechart是使用WINDOWS作?主機運行的 話，可以略過這一段，但如果使用的是UNIX類型的服務器的話，就常常遇到意想不到的中文顯示困難，甚至還未到輸出中文字體的階段，程序就報告 display異常錯誤。原因就在于，JAVA awt原來是針對(X)windows GUI編寫的程序，它常常需要使用display 1:0的設置設定顯示方式，在服務器模式下(象jsp或servlet)，根本就不會有XWindowns運行，這時就會在許多程序中引起can not got display setting to 0:0的錯誤，包括jfreechart。解決辦法是在JVM?動中增加-Djava.awt.headless=true的設置。但這樣又帶來另一個問 題，會令使用象frame.getImage()方法的代碼中引起headless  Exception，導致程序中止,而使用ImageBuffer的程序就不會受到影響。&lt;br /&gt;&lt;br /&gt;象jfreechart這樣基于java awt，java Swing, java 2D API和程序應用到Linux/UNIX上，中文字體的輸出是一個必須解決的問題，否則連jfreereport都不能使用了。servlet也會碰到類 似的問題，但解決方式顯得相對簡單，servlet package已經內置了解決辦法，一般情況下，在 servlet?頭設兩句：&lt;br /&gt;&lt;br /&gt;response.setContentType("text/html;charset=UTF-8");&lt;br /&gt;request.setCharacterEncoding("UTF-8"); &lt;br /&gt;&lt;br /&gt;中文亂碼就不得存在。與簡單的jsp/servlet字符集轉換相比，這個問題要複雜得多，甚至比一般的linux中文化還要複雜。在正常情況下， jre只包含少數幾種字體（Font），但可以從X 系統，象windows獲得喜歡的字體支持；因此，如果開發者和使用者是在中文WINDOWS系統上開發，大概不會發覺問題的存在。但一旦當程序發布到 UNIX/Linux系統上後，就會發現圖形中的中文字符成?一個個的問號或者小方框。而此時，象jsp/servlet這樣的程序在客戶端的顯示卻是完 全正常的。一般情況下，JAVA默認情況下是使用en_OTF-8,或者ISO_8859_1讀入字符串，因此，象JSP通常使用從8859_1強制轉型 ?gb3312/GBK,就可以正常顯示中文，但是在上述的情形下，這種強制轉型地是完全無效的。?什?呢？如果程序員的系統概念是清晰的話，就會明白， JSP/SERVLET的字符串輸出，只是輸出字型，然後由客戶端（一般是?覽器）在客戶端桌面重整字型，用的是客戶端的字體,而相反， JfreeChart這樣的圖形程序輸出的是一個圖像，用的是服務器端jre的字體，與Xwindows的字體也無關。當系統本身不帶有字型時 (font)，這正是服務器所常見的，就只能向jre添加支持中文的字體(font)才能根本上解決這個問題。&lt;br /&gt;&lt;br /&gt;Jre的字體設置原理與Xwindows相似，並延用相同的工具，事實上，二進制字體文件延用相同的標准，各個公司間的字體集，象聯想、方正、微軟以及 linux Xwindows下是相同的，完全可以互相拷貝，僅僅是讀取字體的方式流程和設置方式稍有區別。目錄提及linux漢化的文章，其中主要就是增加中文字體 的支持，很多是廢話連篇，不知其所以然亂撞一通後驚呼"搞定啦"這樣不可重複的形式。所以這?先複習一下，然後和JRE的設置對照，原理就會顯得比較清 晰。目前linux的字體有兩處使用，一是linux console下的字體，二是Xwin等應用程序的字體，包括象zhcon這樣的?console程序。每處應用字體的程序都可以有自已的字體設置目錄； 但隨著Linux集成程度的強化，都傾向向通過默認的unixsocket7000端口調用xfs的字體服務。因此，字體設置只需對xfs進行設置就可以 完成。一些文章聲稱要停掉XFS，實際上毫無必要；xfs的調用僅僅是作?一個在XFConfig中的FontPath選項，作?另一個添加字體的方法， 就是直接把包含字體的目錄添加到FontPath，然後手工執行ttmkfdir——恰恰這本來是xfs設計代替您去做的。用戶實際上需要做的，要?是直 接在圖形工具中把字體文件添加到fonts：\\\中，或者是手工把字體文件加到xfs的目錄下的對應locale的目錄中，一般是在 /usr/share/lib/fonts/zh_CN/TrueType，重?xfs就搞定了。作?手工添加到XFConfig中的目錄，在XWin 中，簡單地說，字體位圖文件是通用的，包括對JRE，放在某一個目錄中，用戶需要做的就是通知XWIN這些目錄在什?地方，設置的位置就在 /etc/X11/XConfig的FontPath項。運行ttmkfdir命令生成fonts.dir文件，實際上都是字體調用的對照表，另外用戶可 以編輯fonts.alias這樣的文件，目的就是讓字體有個易記的名字。因此，字體的安裝關鍵在于字體位圖文件（拷到某個目錄），對照文件（由 ttmkfdir命令生成），和字體別名設置，所不同的是，在Xwin中這些由xfs自動完成，在jre中，就要開發者自已手工完成。&lt;br /&gt;&lt;br /&gt;就Jre而言，字體位圖目錄是固定的，在$JRE_HOME/lib/fonts目錄中;fonts.dir*的目錄對照表文件也是一樣的，同樣是由 ttmkdir程序生成，而相當于別名等設置的文件，集中在$JRE_HOME/lib目錄下的*font.properties*"文件中定義。如果 JVM能直接支持中文輸出，那?就要求*font.properties*屬性文件中指示的字體型本身是支持中文的（換言之，JSDK自帶的字體文件是不 支持中文的）。按http://java.sun.com/j2se/1.3/docs/guide/intl/fontprop.html的說明， JVM按以下順序搜索字體屬性文件,尖括號是JVM檢測的系統屬性：&lt;br /&gt;&lt;br /&gt;font.properties.__.&lt;br /&gt;font.properties.__&lt;br /&gt;font.properties._.&lt;br /&gt;font.properties._&lt;br /&gt;font.properties._.&lt;br /&gt;font.properties._&lt;br /&gt;font.properties._&lt;br /&gt;font.properties.&lt;br /&gt;font.properties..&lt;br /&gt;font.properties.&lt;br /&gt;font.properties.&lt;br /&gt;font.properties&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;但在大多數情況下，實際上只需要面向一個font.properties文件。重新編一個font.properties文件是一項艱苦的工程，幸好在 Linux中有一個font.properties.zh.Turbo，本來是面向TurboLinux用戶，不過在大多數情況下可以基于它修改。把這個 文件重命名?font.properties，覆蓋掉原來的文件，但系統這時仍不支持中文，查看一下，就會發現 font.properties.zh.Turbo文件中的"-tlc-song-medium-r-normal--*-%d-*-*-c-*-gbk -0"字型在fonts.dir對照表中並不具備，這種字型包含在TurboLinux的系統字型庫中。下面的方法有兩個，一是安裝這種字體，二是更改另 一種字體型庫並重新指定。TurboLinux的字體安裝文件名字是ttf-zh-song*rpm，在互聯網上可以找到，安裝後把 /usr/lib/X11/fonts/tt下的ttf文件拷貝到$JRE_HOME/lib/fonts目錄下，重新生成fonts.dir文件。第二 種辦法就是重找字體庫，微軟WINDOWS上的fonts目錄下的ttf文件一般可用，但更全的是從http: //www.microsoft.com/china/windows2000/downloads/18030.asp 下載它的字符集文件，安裝後把ttf拷到JRE的fonts目錄下；另外， XWin如果支持中文的話，可以從/usr/lib/X11/fonts/TrueType下找到一兩個支持中文的字體文件。&lt;br /&gt;&lt;br /&gt;把這些文件統統拷到JRE的fonts目錄並不能令JVM立刻支持中文，回想一下前面提到的，在font.properties中指定的文字類型，必須有 一個對照表fonts.dir指示JVM如何把用戶調用的font類型匹配到相應的字型文件上。因此，運行ttmkfdir &gt; fonts.dir生成新的對照表。用Vi打開這個文件，最上面的數字是系統可以調用的字型數目，下面的屬性值對左側就是物理字型名稱，右側是它的編號， 這就是用到font.properties 文件中指明使用的編號（包含了設置，左側的就是字符的別名，即虛擬字型)，區別僅僅是把0-0-0c-0這類設置中的某幾項改作通配符和%d接受調用參數 而已，不改也行，大不了輸出的字難看一點（反正我不是美工，不太關心）。用可用的字型編號代替了font.properties中無效的字型設置後，理論 上似乎JVM已經支持中文了，但在實際操作上，仍是經常見到問號、空格之類，原因就在于JAVA對中文的支持不但與運行環境有關，還與編譯參數有關，如果 類文件不是以gb2312/encoding編譯的話，等同于讀入是OTF-8/8859_1，這時再轉換也沒有用了，因此，如果是drawString 之類的，必須切記使用(-encoding gb2312)；當然，如果操作系統本身已經是中文的話，這條就由編譯器自動采納了。&lt;br /&gt;&lt;a href="http://blog.csdn.net/zwwwxy/archive/2005/03/29/333441.aspx"&gt;http://blog.csdn.net/zwwwxy/archive/2005/03/29/333441.aspx&lt;/a&gt;&lt;br /&gt;&lt;a href="http://zwwwxy.blogchina.com/294399.html"&gt;http://zwwwxy.blogchina.com/294399.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://javaxml.blog-city.com/unixlinuxjavajvm.htm"&gt;http://javaxml.blog-city.com/unixlinuxjavajvm.htm&lt;br /&gt;&lt;/a&gt;&lt;a href="http://javaxml.blog-city.com/jfreechart.htm"&gt;http://javaxml.blog-city.com/jfreechart.htm&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871251569815939?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871251569815939/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871251569815939' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871251569815939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871251569815939'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/unixlinuxjavajvm.html' title='在Unix/Linux上令(java)JVM支持中文輸出'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-13650940.post-111871222953251135</id><published>2005-06-13T17:42:00.000-07:00</published><updated>2005-06-13T18:23:49.536-07:00</updated><title type='text'>JAVAFREECHART對象關系</title><content type='html'>jfreechart是一個優秀的開源JAVA 2D項目，缺點是缺乏文檔，中英文都是如此。本文是經驗總結的第二部分&lt;br /&gt;&lt;br /&gt;二、jfreechart作圖類對象的協調關系&lt;br /&gt;&lt;br /&gt;jfreechart的繪圖對象由一個org.jfree.chart.JFreeChart組成，但作?繪圖關鍵的Graphich2d通過 org.jfree.chart.render.*中的對應render類包裝後設入，換言之，開發者可以通過對基礎圖板Graphic的設置，完成必要 的繪圖預定效果設計；而大多數的修改，實際上可以通過包裝的各個類操作而不用直接修改Graphic對象屬性（誰記得呢？）。jfreechart的數據 接口由org.jfree.chart.plot.*中的不同的plot包裝，與之相對應的是不同的dataset,位于 org.jfree.chart.data.*中不同的dataset接口包裝。使用jfreechart作圖的關鍵在于生一個個相應的數據集對象，，然 後包裝成對應的一個個繪圖集plot對象，最後再包裝成不同的JFreeChart對象交付輸出。通過new方法可以一步步完成上面的步驟。換言之， plot類是圖形的設計，render 是繪制的工具，而dataset則是填充的數據；這樣就把作圖的三個關鍵因素分別抽象成統一的接口，互想搭配出各種圖形。對于可能有多套數據集的圖表，如 時間序列的多條曲線走勢圖（象幾只股票），傳入plot的不是數據集，而是數據集的集合，一般命名?某某collection。&lt;br /&gt;&lt;br /&gt;通過ChartFactory的不同方法生成不同的Chart類型，可以相應地縮小了由dataset對不同的chart對象的操作過程代碼量，直接獲得 chart對象。實際上是由工廠類代替用戶生成必要的render和plot類，如果用戶不想使用默認的設置，就需要再通過get方法得出相應的plot 對象進行修改。jfreechart的最後圖像輸出一般由org.jfree.chart.ChartUtilites完成，這個類可以向接定的 PrintWriter對象輸出完成的Chart對象。在服務器程序中，另一個ServerUtilites方法調用了這個方法，生成一個圖像臨時文件， 並向JSP或servlet返回這個文件對象，通過把這個圖像的生命周期與session綁定，希望可以實現緩沖功能，降低服務器動態生成圖像的損耗。但 是也有很大的問題其一就是如果session很長，就等于不能生成實時圖像，其二就是訪問的人多了，服務器的負擔似乎反而加大了。這個算法顯然有問題，倒 不如修改成按時間更新一個圖像更?合適。&lt;br /&gt;&lt;br /&gt;觀察代碼，兩者效果是一樣的：&lt;br /&gt;&lt;br /&gt;A、工廠方法：&lt;br /&gt;&lt;br /&gt;JFreeChart chart = ChartFactory.createPieChart3D(  "2000 GDP分布比例圖",  data,  true,  false,  false  );//指定獲得不同的實現chart對象，含有不同的plot繪圖對象&lt;br /&gt;  &lt;br /&gt;PiePlot plot = (PiePlot) chart.getPlot();//獲取plot對象用于修訂屬性，強制造型，以便調用各自的方法&lt;br /&gt;plot.setLabelGenerator(new StandardPieItemLabelGenerator( "{0} = {2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance() ));//設定注釋方式&lt;br /&gt;plot.setForegroundAlpha(0.5f);//設定透明度&lt;br /&gt;plot.setNoDataMessage("無記錄內容");//無記錄異常顯示&lt;br /&gt;&lt;br /&gt;B、手工生成對象&lt;br /&gt;&lt;br /&gt;PiePlot plot = new PiePlot(dataset);&lt;br /&gt;&lt;br /&gt;plot.setLabelGenerator(new StandardPieItemLabelGenerator( "{0} = {2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance() ));//設定注釋方式&lt;br /&gt;plot.setForegroundAlpha(0.5f);//設定透明度&lt;br /&gt;plot.setNoDataMessage("無記錄內容");//無記錄異常顯示&lt;br /&gt;&lt;br /&gt;JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13650940-111871222953251135?l=javaxml.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaxml.blogspot.com/feeds/111871222953251135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=13650940&amp;postID=111871222953251135' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871222953251135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13650940/posts/default/111871222953251135'/><link rel='alternate' type='text/html' href='http://javaxml.blogspot.com/2005/06/javafreechart.html' title='JAVAFREECHART對象關系'/><author><name>China GadBee</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
