1、介紹
通過證書驗證用戶身份(瀏覽器),其核心是利用cookie實現http和https的信息共享(同域名)。如http://test.abc.com/app/index.html 發現未驗證后,跳轉到https://test.abc.com:443/app/checkCrt.html身份驗證,要求出去證書,確認后將身份信息帶入http請求頭部,跳轉到原請求頁面(http://test.abc.com/app/index.html ),讀取身份信息后進入頁面(出于安全考慮Cookie需要加密)。
流程圖

流程說明:
登錄流程詳細介紹:
1). 未登錄用戶訪問頁面 如:http://test.abc.com/app/index.html
2). 【CertAuthValve】判斷是否訪問受限制資源,如訪問受限制的資源則判斷用戶身份是否已驗證,未驗證則將用戶重定向到身份驗證頁面,原始請求的url做為
query的一部分,登錄成功后可以跳轉回來, 如:https://test.abc.com:443/app/checkCrt.htm?done=/index.html。
3). 【CertAuthValve】對于https請求,apache讀取請求提供的用戶證書,獲取證書中的郵件地址,并將該信息寫入請求頭中。
4). 【GetUserInfoValve】讀取請求頭,獲取剛剛設置的用戶郵件地址信息,進一步獲取用戶的詳細信息,然后將這些信息加密后放入cookie中。
5). 登錄完成,將用戶外部重定向回原始頁面。
2、具體實現
1)、安裝apache、ssh、java、jboss等環境,略。
2)、生成服務證書和服務密碼
openssl req -new -x509 -nodes -out /home/admin/app/conf/ssl.crt/server.crt -keyout /home/admin/app/conf/ssl.crt/server.key -days 3600
因為要和內網證書交互,所以需要一個內網證書公鑰文件,可以通過以下方式獲取:
獲取方法:IE->工具->Internet選項->內容->證書->受信任的根證書頒發機構,找到intranet行,點擊導出,選擇下一步,選擇Base64編碼X.509,將證書文件保存為intranet-ca.crt,拷貝到目錄/home/admin/app/conf/ssl.crt/。
3)、apache(httpd.conf)配置
應用和身份驗證頁面放在一起,所以需要同時配置兩個虛擬主機,同時監聽80(處理http請求)、443(處理https請求)端口。
#監聽端口Listen 80Listen 443#app的虛擬主機配置NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin sa@abc.com
ServerName test.abc.com
DocumentRoot /home/admin/app/target/app/htdocs/
</VirtualHost>#身份驗證的虛擬主機配置NameVirtualHost *:443
<VirtualHost *:443>
ServerAdmin sa@abc.com
ServerName test.abc.com
DocumentRoot /home/admin/app/target/app/htdocs/
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+SSLv3:+EXP:+eNULL
#該指令為虛擬主機指定證書文件名。
SSLCertificateFile /home/
admin/app/conf/ssl.crt/server.crt
#該指令為證書指定一個對應的私鑰文件
SSLCertificateKeyFile /home
/admin/app/conf/ssl.crt/server.key
#該指令為指定一個包含Certificate Authority證書的文件
SSLCACertificateFile /home/admin/app/conf/ssl.crt/intranet-ca.cer
SSLProxyEngine on
RewriteEngine on
#設置客戶端證書驗證為必須
SSLVerifyClient require
#因為一個CA證書能夠被另一個CA證書驗證,所以可以形成一個CA證書鏈.使用該指令可指定服務器驗證用戶證書時可以查找多少個CA證明。
#設置認證深度:一般用默認10。
SSLVerifyDepth 10
#把mod_ssl里的變量變為全局環境的變量
RequestHeader unset SSL_CLIENT_S_DN_Email
RequestHeader add SSL_CLIENT_S_DN_Email %{SSL_CLIENT_S_DN_Email}e
</VirtualHost>
4)、代碼片段
//CertAuthValve.java
//判斷session中是否有用戶郵箱地址
SessionValue session = SessionHelper.getSessionValue(rundata);
if (StringUtil.isNotEmpty(session.getCropEmail())) {
return null;
}
// 從內網證書中獲取用戶郵箱地址: SSL_CLIENT_S_DN_Email
String cropEmail = rundata.getRequest().getHeader(SSL_CLIENT_HEADER_MAIL);
if (StringUtil.isNotEmpty(cropEmail)) {
//將郵箱地址保存到session
session.setCropEmail(cropEmail);
SessionHelper.saveSessionValue(rundata, session);
if (log.isDebugEnabled()) {
log.debug("用戶" + session.getCropEmail() + "已經通過證書驗證");
}
return null;
}
URIBrokerService uriBrokerService = (URIBrokerService) getWebxComponent().getService(
URIBrokerService.SERVICE_NAME);
URIBroker noPermissionUriBroker = uriBrokerService.getURIBroker(CHECK_CRT_URL);
//請求的原始URL & 驗證的URL
String requestPath = rundata.getPathInfo().replace("_", "");
String checkCrtUrl = (String) noPermissionUriBroker.getPath().get(
noPermissionUriBroker.getPath().size() - 1);
try {
//原始請求判斷
if (requestPath.equalsIgnoreCase(checkCrtUrl)) {
//當前是https請求,但是依然不能得到證書信息,轉到禁止頁面
//(要將禁止頁面加入到允許訪問的配置文件中,不然會導致循環重定向)
URIBroker uriBroker = uriBrokerService.getURIBroker("forbidden");
rundata.setRedirectLocation(uriBroker.render());
} else {
//轉到證書驗證頁面
rundata.setRedirectLocation(noPermissionUriBroker.render() + "?done=" + rundata.getPathInfo());
}
} catch (IOException e) {
log.error("權限驗證重定向出錯", e);
}
return new BreakPipeline();
//GetUserInfoValve.java
Object user = rundata.getSession().getAttribute("userInfo");
if (user == null) {
SessionValue session = SessionHelper.getSessionValue(rundata);
String email = session.getCropEmail();
Employe employe = PersonInfoUtil.getPersonInfoByEmail(email);
// 寫入cookie
session.setEmployeeId(employe.getEmployeId());
session.setName(employe.getName());
session.setCropEmail(employe.getEmail());
SessionHelper.saveSessionValue(rundata, session);
}
采集到花瓣
posted @
2011-12-09 16:09 josson 閱讀(2441) |
評論 (0) |
編輯 收藏
受限于證書的原因,以前經常不得已用IE打開一些應用。其實有一工具可以幫助我們導出IE證書,用于firefox,解決證書的困惑。
采集到花瓣
posted @
2011-12-09 13:54 josson 閱讀(3107) |
評論 (1) |
編輯 收藏
互聯網的產品大都是面向海量用戶的服務,且用戶分布區域廣泛,其教育水平、習慣也大多不同,具有高度不確定性,我們必須非常關注用戶的行為和反饋。因而,在互聯網產品服務的整個用戶研究,需求分析、產品研發及交付服務的過程中,都采用探索式、適應性的研發理念進行產品的研發。通常,會把整個產品研發周期劃分為若干個迭代,采用迭代式的演進過程,不斷的去交付新的產品特性,并通過觀察用戶的行為和反饋獲取,進而隨時調整產品的思路和方向。一切以用戶價值為核心是互聯網產品最核心的特點,而以價值驅動的敏捷開發方法非常符合這一特點。
一、敏捷項目管理實踐 
從阿里軟件開始,內貿團隊就一直在實行著敏捷項目管理實踐,通過小步快跑,快速迭代、增量交付用戶價值,不斷獲取用戶反饋,持續、快速的調整產品,驗證并適合用戶價值。正是通過這些實踐活動,我們以迭代的、增量的交付用戶價值,最大限度的保證產品朝著符合用戶實際需求方向發展。目前,在內貿團隊應用較成熟的敏捷實踐活動有:
1)、迭代計劃(Sprint Planning Meeting)
2)、每日晨會(Daily Scrum Meeting) & 任務墻(Task Wall)
3)、功能預演(Spring Review)
4)、項目總結(Retrospect Meeting)
5)、結對編程(Pair Programming)
6)、其他技術實踐活動等
二、敏捷團隊
1)、自組織文化
如google、facebook等互聯網企業,他們很少甚至沒有特定的項目流程,通常怎么敏捷怎么做,具有濃厚的工程師驅動文化。我們則有較完整的開發流程指導和規范我們的項目研發工作,相比而言,喪失了一些靈活性和積極性,不利于我們工程師自我管理、自我驅動意識的培養。臃腫、缺乏靈活性的流程同互聯網產品快速更新、快速發展是不相適應的,同時也弱化我們的責任心意識。除了遵守詳盡的流程,我們是否可以換個角度、換種方法,提倡和營造一種自我管理、自我驅動的開發文化,省卻一些并不能給我們帶來幫助卻影響效率的流程呢?
敏捷團隊的自組織特性弱化了團隊技術領導這個角色,強調自我管理和自我驅動。雖然這對工程師的素質要求更高,相對技術能力更難提高。但是,團隊導向很重要,我們努力營造這樣的氛圍,從小團隊做起,逐漸鍛煉和培養自組織團隊。相信在這樣的開發氛圍下,會讓我們做的更高效、更敏捷,可以走的更穩、更遠。
2)、追求一體化
一體化團隊作為敏捷開發方法中最具精益思想基因的實踐,是指每個項目團隊包括分析,開發,測試等角色,使團隊滿足一個需求從設計,開發到測試各個階段順利完成,達到符合質量標準并滿足需求的軟件。這種以項目/產品為單位的虛擬團隊,坐在一起,全身心的為共同的目標而努力,可以更好的凝聚項目組中的各種角色,消除部門墻。
3)、追求全功能
這里所指的全功能是希望項目團隊能打破工程師角色之間的邊界,如研發、測試和前端工程師的界線,消除開發、測試流程中一些潛在浪費,提高效率。在項目團隊內部通過角色互換,不限角色的結對工作,加強不同角色,不同模塊間的知識傳遞,打破技術壁壘,幫助員工從不同視角理解項目,鍛煉技能,進而增加團隊均衡生產的能力。
為什么要提倡打破邊界?項目整體效率依賴于項目過程中各環節的工作效率,而整體效率的優化往往依賴于均衡生產(精益思想的按需生產),即消除生產的波峰(過度生產)和波谷(生產不足),只有局部效率的增加無法直接轉換為整體效率的增加(就象桶能裝多少水,決定于最短的那塊板)。整體效率的優化要求IT團隊消除技能壁壘,培養多面手,根據計劃的的變動,彈性地調整任務,達到各角色和流程之間的平衡。
三、質量保證
我們追求開發效率,同時也注重項目質量。如何去保證質量?就象美國的一位教授愛德化.戴明(W.Edwards Deming)所說:“我們應該停止依靠大量檢驗來保證質量,而是要改進工藝流程,從一開始就生產出優質的產品”。我們要在整個開發過程中多個環節去保證質量。同時,質量保證是整個團隊的責任,就如同前面所說的追求全功能團隊,打破邊界。
至于在哪些環節采用哪些實踐,我們先做個分類,按是否能被系統用戶感知將質量問題區分內部質量和外部質量。外部質量指能直接被系統用戶感知,如運行緩慢,不可操作或是操作復雜就屬于外部質量低劣。而不能直接為系統用戶所直接感知的要素,對產品鍵壯性、可維護性有深遠影響的問題就屬于外部質量,如系統設計的一致性、代碼可讀性、邏輯完整性等。內部質量對用戶的影響比較間接,但比外部質量意義更深遠。一般來說,系統內部質量優秀,外部質量仍有可能很差。而內部質量差的系統,外部質量肯定也不怎么樣。
1)、外部質量保證
在外部質量保證上,大部分會在開發后期介入,可以通過性能測試、自動化測試及工程師的功能測試來保證,通過這些實踐活動發現并保證例如運行緩慢、不可操作等質量問題不會存在。針對交互特別復雜的web應用,可以更多的考慮采用webui自動化測試工具,如selenium、pwaitr(b2b)、automan(淘寶)等,可以很好的完成那些簡單、重復的TC用例,可以大大提高測試效率,解決測試工程師的資源瓶頸。
2)、內部質量保證
相對于外部質量,內部質量問題影響更為深遠,在開發開始階段就應該去保證。如通過單元測試、靜態代碼掃描(PMD\findbugs)、持續集成、重構、結對編程、code review等多種實踐活動來保證項目代碼的健康。
除了一些實踐活動去檢查代碼質量外,更為重要的是研發工程師對內部質量的重視,如果工程師沒有形成良好的質量意識,很可能這些實踐也只是停留于形式,并不能帶來較好的結果。如我們在開發過程中的編碼規范、單元測試的質量及覆蓋率,code review的及時性及問題是否持續跟進等等。此外,有選擇的采用結對編程實踐,有助于質量的提高。
本文以敏捷、精益(消除浪費、按需生產)思想的角度試圖去探討一種適合互聯網公司的產品開發體系,上述概要的介紹了項目管理、團隊、質量方面的一些敏捷實踐活動,主要涉及了我們對敏捷方面的經驗分享或者是些正在研究探討的課題。文中涉及的實踐活動,后續我將逐一展開詳細介紹,幫助大家更好的理解和認識。希望本文的分享能成為一個引子,引起大家對敏捷開發的思考和討論,或者更好的了解敏捷和精益思想。
posted @
2011-06-13 15:53 josson 閱讀(524) |
評論 (0) |
編輯 收藏
以下為本人在公司內部關于項目質量和工作效率郵件回復的一此意見和想法。
1、 談流程
不可否認流程的重要性,但我們需要根據具合格情況分析,不斷的梳理和優化我們的流程,讓流程更好的指導我們工作,而不是束縛。目前,我們的流程慢慢多了起來,感覺不如以前敏捷了。經過rpm改造后,無論在測試環節還是發布階段,較之前失去了很大的靈活性。測試階段,開發bugfix后想在測試環境驗證,每次必須重走aone的流程及打包布署,相比之前的build效率真的差了好多。當然,也許是我們項目組對這個流程熟練度、方法還不夠,很多環節有待改進。
發布階段,目前統一由SCM來發布,必然會導致開發對線上環境及發流程更加陌生,同我們提倡的打破邊界,敏捷響應有些相背。再者,SCM資源有限的原因,要支持ITU眾多產品線,能否應付的過來,始終是個問題。發布統一管理有好處,同樣也帶來了弊端,ITU不同于網站,大多數的技術團隊共同在維護在幾個應用,而itu的應用多、規模相對小、環境各異,這樣的產品線采用統一管理性價比不高。希望相應的owner,能不定期的搜集各產品線的意見和反饋,不斷的優化,讓我們的流程更合理。
2、 談自測
我們團隊一直在強調自測意識,也在這方面不斷的總結和改進。我覺的要提高自測,首先應讓每位開發同學形成較好的自測意識,而不是自上而下的命令式管理,只有自己有這方面的意,才會去思考、去想辦法,去實踐。再者,需要PM或技術經理去思考,目前階段實行自測會有什么困難,如沒有系統的自測方法、時間不充足(需要熟悉下階段的UC、下迭代的設計、單元測試補寫等),找到這些困難或問題,就容易對癥下藥了。最后,不斷總結和積累自測方式,優化項目流程。自測不是一種形式,而要追求效果,開發自測同樣需要計劃和方法,所以我們需要向QA同學請教,總結過去 bug常犯的錯誤,整理自己的check項。相信通過這樣的一些自測方法,能真正提高我們的項目質量,打破同QA的界線,我們的開發、測試資源比例可以得到更大的優化,將以前開發階段緊,測試階段松的狀況加以改善,使整個項目過程中的緊張度趨于平緩。
3、 談故障分
“盡量不要讓故障分成為大家包袱,可以考慮被實施產品對事故級和A類才對個人計故障分,B和C類故障分記在主管頭上!”,個人也比較支持駱駝的觀點。目前大家對線上故障都小心翼翼,大家對質量的意識很高,這當然是好事,但同時帶來的影響是效率低了。我的觀點是,作為增值服務的互聯網產品,我們更需要快速迭代增量提供用戶價值,盡快獲取用戶反饋并改善產品,產品推出的遲早,不僅影響獲得回報的時間,還影響到獲得價值的多少,錯過了一個時間窗口,產品可能就不再有任何價值。所以,我們需要找到一個平衡量點,可接受的質量狀況達到最大的效率。
從客戶第一角度談質量,某些時候,客戶可以接受服務偶而不可用重啟下,卻不能接受產品沒價值、交互性太差,操作太復雜。所以,對于客戶來說什么對他們更重要,就需要我們每個人去分析和評估。所以,我們一味只注重質量,而忽略客戶真實需求,那就太悲哀。我的觀點是,case by case,帶著這樣的觀點去思考和解決問題。
4、談敏捷項目團隊
從打破邊界,我想到了一體化的敏捷項目管理團隊,一個目標一致、自我管理的團隊,應該具備良好的目標意識和執行力,不僅能管好自己的一畝三分地,同時也能站在項目、團隊的角度看待問題。PD出現了問題,開發積極去彌補;開發出現了問題,QA積極去彌補,項目團隊的目標非常一致。每位項目組成員一定要把好每一關,萬不可把問題向下拋,因為還有開發或QA會把關,所以差不多就行了,這樣往往就是災難的開始。
posted @
2011-05-20 16:39 josson 閱讀(480) |
評論 (0) |
編輯 收藏
2010已成為歷史,記憶里2010年變化很多、做的很多、收獲也很多。2010是個轉型期、創業期,從年初開始,就在新的Marking中努力耕耘。前半年,以新產品研發為主;后半年,結合客戶使用產品后的反饋,不斷的優化和改進產品功能,努力提升產品價值和用戶體驗。通過大家的努力,幾款新產品還是彼受用戶歡迎的,最欣喜的是我們提前完成了2010年的KPI目標。
過去的一年,有著太多的痛苦和艱辛,為了新產品的上線,晚上、周未都沒了,唯一想的和做的就是確保產品如期上線。過程雖然很艱苦,但大家都努力堅持,齊心協力,確保任務如期完成,我們保持了一貫的說到做到、如期交付的作風。因為這樣的磨練,我和我們的團隊得到了更多成長。困難并不可怕,熬過去,明天的太陽會更加燦爛。
1、談談成長和不足:
1)、職業轉型,開發到管理
雖然Team Leader已經做了幾年了,但一直停留在項目上,多為管事不管人,對細節問題關注較多,所以之前談不上管理,只能算是積累些項目管理經驗。經過這一年的學習和發展,有了更多的管理意識,逐漸關注團隊建設、團隊成長,注意給小組成員更多的機會和空間,讓他們得到鍛煉和成長,承擔更多團隊或項目中的重要事項,而他們通過完成這些重要任務,不僅得到了磨練,同時在團隊中建立了自己的影響力。
放在以前,我會認為有風險,或者自己做更快,更省事,或最有把握的人去。現在想來,以前認識太膚淺了,我們需要的團隊戰斗力,而不是個別人的能力,若平常不注重團隊成員的培養,團隊的戰斗力永遠不行,承擔不了關鍵任務。
談到成長和培養,團隊需要什么樣的人呢?作為互聯網企業,同一般軟件企業不同,產品在推出之前,誰也無法肯定是否會受用戶歡迎,只能快速推出,讓市場來驗證,不斷的改進和適應用戶的需要。因而,需要我們技術人員也具備技術判斷力,改變命令式管理體制下的工作習慣,充分發揮主觀能動性和創新意識,共同做好產品。
2)、學會擁抱變化;
2010年變化很多,有些也許對個人、團隊沒有影響或影響很小,有些直接關系自己或團隊,如團隊的核心成員不斷的被抽調、人員調整、KPI的271考評等,每次的變化都會帶來不同的問題。持續輸血,新人補允,使團隊戰斗力大打折扣,很長一段時間非常的糾結和無耐。事情總是具有兩面性,往好處看,這對我、對團隊也未必是件壞事,沒有經驗過挫折和磨練,又怎能成佛呢?既然是組織需要或Boss的決定,那就多些理解和支持,支持和協助上級完成也是每個下屬的職責;況且,某些變化至少對于一些同學也是件好事,他們有更多的機會和更大的平臺去一展才華。
大概人都是喜歡按習慣辦事的緣故,每每有變化都覺的很痛苦。我覺的如何擁抱變化關鍵在于心態,我們需要理性看待變化,多往積極的方向思考,不僅更容易調整好心態,而且可以在變化中吸取經驗和教訓,鞭策我們成長。
3)、提升項目管理能力
雖然在項目管理知識上沒有太多的時間和精力去系統的學習,但通過不斷實踐和總結,還是有了不少的積累和沉淀,對項目管理有了更多的理解和把握,對敏捷項目管理也有不同的認識,結合團隊自身尋找適合我們的實踐方式。在項目管理方面,還有很多需要去提升和學習,2011年希望安排更多的時間系統的學習項目管理知識及敏捷項目管理,并結合實際應用到工作中。
4)、提升向上溝通力
在擁抱變化的同時,同樣需要理性的分析和積極的向上溝通。在過去,雖然會盡可能的去表達和反饋自己的想法和意見,但我重新審視下,總覺得表達還不夠明確或不是那么的到位,或許在表達時還有更好的方式,至少還有提升的必要。向上溝通也是門學問,需要好好研究下。
5)、提升團隊建設和輔導能力
相對來說,過去的一年所有的同學都會關注到,但領悟能力和基礎較好的同學成長更快,基礎稍弱的沒有太大變化。顯然,平常輔導工作沒有做好或做到位,關注程度不夠。越是基礎差些的同學需要關注和幫助的點越多,需要幫助他們找到不足和問題所在,一起找改進辦法,并給予必要的督促和檢查,養成好的學習習慣,促進成長。2011年,這方面需要做的還有更多。
2、談談2011年的期望
1)、團隊
解決目前團隊新人多,有效資源少的問題;積極關注和幫助新人溶入團隊,熟悉業務,以減少對項目開展的影響;
抓好梯隊建設,關注和輔導基礎較差同學的,共同制定改進計劃和Action,做好必要的監督和指導,促進成長;
2)、能力
系統學習項目管理和敏捷軟件開發方面的知識,并應用到項目管理實踐中;同時積極參與相關方面的分享和討論。
3)、影響
推動興趣小組活動的開展,借開發工具的發展和分享,建立團隊在部門或技術部的影響;
鼓勵團隊成員積極參與技術部的公共事務,提升影響力。
給力2010,加油2011!!!
posted @
2011-02-02 21:46 josson 閱讀(312) |
評論 (0) |
編輯 收藏
1、什么是iteration和release?
iteration和release是兩個不同的概念,但在敏捷實踐活動中,我們往往認識的比較模糊,一個Iteration就是一次release,其實不然。那么,具體有什么區別和聯系呢?
Iteration(迭代):在固定的周期內,經過需求分析、設計、實現、測試等活動,完成計劃的的業務需求,迭代結束提供一個可工作的產品。計劃的業務需求,可能是一個完整的User Story,也可能是一個Story中的若干task。
Release(發布):經過一個或若干個iteration后,完成計劃中的所有User Story,經過測試后才release,最終真正交付給客戶使用。
在我們的實踐活動中,一個User Story所需的工作量超過我們的有效資源,無法安排在一個iteration內。我們就會想當然的會去延長迭代周期,增加有效資源以適應所需工作量。殊不知,這更象是形式上的迭代開發,無異于瀑布式項目開發過程。
2、建立固定的迭代周期,保持穩定的開發節奏
Scurm方法也非常強調穩定的迭代節奏,一個穩定的迭代節奏就如同項目的的心跳。Simon Baker描述說:"就像心臟有規律地跳動來保持身體運行,固定的迭代長度提供了一個恒量,有助于建立開發和交付的節奏。根據我的經驗,節奏是幫助取得不變的步幅的重要因素"(2004)。對于敏捷開發的團隊而言,穩定的迭代節奏可以讓產品保持更穩定的交付。
3、如何保持穩定的開發節奏?
當一個迭代期內可提供的有效資源無法實現一個User Story時,我們如何按排呢? 在 談迭代周期控制的困惑 中已談到,這里不在細述。
4、如何選擇適合自己團隊的迭代周期?
一般需要考慮以下因素:
1)、整個項目周期長度(完成計劃的商業需求所需時間)
較短的迭代周期將會有以下一些好處:更頻繁的向客戶展示/交付可用的軟件;更頻繁的度量開發進度;更頻繁的取得反饋并改進;一般大的項目最好有多次(3次或以上)獲取反饋、修正的機會,根據項目周期調整迭代周期長度。
2)、不確定性的多少
不確定性有多種形式,客戶到底想要的是什么?小組的工作效率,時間?技術門檻等都不存在不確定性,不確定性越多,迭代就應該越短。
3)、獲得反饋的難易程度
指小組獲取反饋數量、頻度和及時性,視所處的環境不同,選擇合適的迭代長度;
4)、優先級要以多久保持不變
開發小組承諾在一次迭代中完成一組特定的功能,重要的是不要改變他們的目標方向,優先級不會被改變的時間長度是選擇迭代長度時需要考慮的因素。
5)、迭代的系統開銷
每次迭代的成本(時間),如迭代中進行的完整回歸測試。最佳迭代周期的目標之一就是減少或近似消除每次迭代的系統開銷。如每次回歸時間成本很高,那決定周期長度時更傾向于長一些。
6)、團隊成員的緊迫感
Niels Malotaux指出:"只要項目的結束日期還在遙遠的將來,我們就不會感到任何壓力,并從容不迫的工作。當結束日期逼近時,我們才會開始更努力的工作"。意思指項目開始大家比較放松,而越臨近結束,工作越忙壓力越大。因此,選擇一個合適的迭代周期長度,讓團隊成員在整個迭代過程中感受到的壓力更平均,不是給團隊更多的壓力,而是壓力總量平均分布在迭代過程中。
每個團隊根據所在環境和條件確定一個合適的迭代長度,一般建議2~4周。在我們的實踐中,以2周一次迭代的頻率,保持相對穩定的開發和交付的節奏。
5、參考資料:
《敏捷估計與規劃》 Mike Cohn
posted @
2011-01-31 14:26 josson 閱讀(3418) |
評論 (0) |
編輯 收藏
敏捷宣言中說到:"最好的架構、需求和設計來自于自組織的團隊"。在自組織團隊中,我們每個人既是團隊/項目的管理者,又是執行者,要取得優異的結果,必須加強自我管理。
如何做好自我管理呢?
1、平和的心態:我們會不斷的遇到各類或好事或壞事、或成功或挫折,什么樣的心態去對待決定了我們成長的方向及高度,"態度決定一切"。
2、目標感:大到個人職業規劃,小到每件事的期望,對于目標(期望)的制定和管理,都需要我們認真的去對待;
3、執行力:目標是方向,不能執行就不會有結果,好的執行力是優秀個人或團隊的必要條件。
4、時間管理:工作需要區分輕重緩急,不能對事情沒有計劃和按排,對事需要分析重要性和緊急程度,分別對待;
5、學習能力:"學歷代表過去,能力代表現在,學習能力代表將來。",一個人的學習能力決定他將來的成績;
任何人都不希望自己被人管著,但要想不被人管只有一種辦法:時時嚴格要求自己,主動、出色的完成每項工作,努力學習,與團隊共成長。




posted @
2011-01-28 18:56 josson 閱讀(271) |
評論 (0) |
編輯 收藏
昨日PM小組例會,談到了需求評估工作量遠大于有效資源情況下,如何保證迭代周期穩定的問題。討論的內容,對于PM如何控制、保持迭代周期穩定有較大的參考價值。
|
有效資源 |
評估工作量 |
1 |
多 |
少 |
2 |
少 |
多 |
3 |
相同 |
相同 |
注:
有效資源:指迭代周期內,開發團隊所能提供的有效工作日,單位人/天。
評估工作量:指迭代周期內,產品經理提供需要實現的業務需求所評估的工作量之和。
上表描述以固定周期為兩周的迭代中,可能會出現的有效資源和評估工作量對比情況。其中,1、3兩種情況因為評估工作量小于或等同能提供的有效資源,所以不會影響迭代周期。重點需討論的是有效資源小于評估工作量時,如何保持固定周期?
例舉:一迭代周期,能提供有效資源20人/天,需求評估工作量30人/天。
1、功能較獨立,需求不能拆分發布;
安排一個release,兩個iterative。這種情況需要在迭代2中附加一些技術改造或低優先級的小需求、bugfix,release日期相對會慢幾天。
2、一個迭代中包括多個產品的需求(需要各位產品經理協商,決定需求優先級);
a)、以保證質量為重:
忽略商業優先級,先處理一個迭代中就能全部完成的需求。
b)、保證價值
分兩個迭代完成,一次release。
通常情況下,我們盡力保證迭代周期的穩定,但也允許例外,如:商業需求,產品上確定了發布時間點,或者節假期間團隊請假比較多,一個迭代所能提供的有效資源相對比較少的情況。
保持迭代周期穩定,其核心是:
固定Timebox和可提供的資源,讓產品經理來決定需求的優先級,每迭代只接納(開發/QA資源)可承受的需求。
posted @
2011-01-13 15:31 josson 閱讀(1024) |
評論 (0) |
編輯 收藏
對于互聯網行業來說,快速推出產品占領市場、快速檢驗產品的價值和方向性、快速調整及優化是極期重要的。因此,采用小步快跑、持續迭代的敏捷實踐一種不錯的項目管理方法。我們團隊在敏捷項目管理方面持續開展了二年多時間,在scrum、xp等敏捷最佳實踐的基礎上,結合團隊自身的基礎和條件,不斷的償試和優化,總結和積累了一些經驗。目前,這些敏捷項目管理實踐在項目組開展情況良好,得到了大多數團隊成員的認同,特別是業務方、QA等合作方的認可。

上圖描述了一個基本項目迭代流程,其中涉及三個角色,其職責同等于Scrum中的Product Owner、Scrum Master、Scrum Team。迭代流程中分別包含了以下敏捷實踐:
1)、迭代計劃會議,按商業優先級篩選需求列表,確定本項目需求范圍;
2)、確認本次迭代需求、資源、時間的具體情況;
3)、簡單設計,對關鍵技術點進行必要的設計;
4)、晨會;
5)、結對編程;
6)、持續集成;
7)、showcase;
8)、項目總結會;
9)、新迭代的開始... ...
以上具體實踐活動內容及組織形式,后續將逐一介紹,敬請關注。
posted @
2010-12-16 15:57 josson 閱讀(344) |
評論 (0) |
編輯 收藏
1、什么是java序列化
Java
序列化
API
提供一種處理對象序列化的標準機制。序列化(Serialization)是指將java對象用一連串字節描述的一個過程;反序列化(deserialization)是一種將這一串字節構建成一個對象的過程。
2、序列化的作用(必要性)
Java中,一切都是對象,在分布式環境中經常需要將對象從這一端網絡或設備傳遞到另一端。Java
序列化機制就是一種解決在網絡兩端傳輸數據的問題而產生的協議。下圖表示客戶端/服務器之間通信,一個對象是從客戶端傳送到服務器通過序列化的視圖。

3、如何序列化一個對象
為序列化一個對象,你需確保對象類實現Serializable接口。Serializable接口沒有方法,只要實現了序列化接口,Class
就能被序列化機制處理。
示例代碼,需序列化的java對象:
1 import java.io.Serializable;
2
3 public class TestClassSerial implements Serializable {
4 public byte version = 100;
5 public byte count = 0;
6 }
示例代碼,
把TestClassSerial對照象
輸出成
Byte
流,存儲到
temp.out
文件里:
1 public static void main(String args[]) throws IOException {
2 FileOutputStream fos = null;
3 ObjectOutputStream oos = null;
4 try {
5 fos = new FileOutputStream("c:/temp.out");
6 oos = new ObjectOutputStream(fos);
7 TestClassSerial tcs = new TestClassSerial();
8 oos.writeObject(tcs);
9 oos.flush();
10 }
11 finally {
12 if(oos != null) {
13 oos.close();
14 }
15 if(fos != null) {
16 fos.close();
17 }
18 }
19 }
示例代碼,
從持久的文件中讀取
Bytes
重建對象:
1 public static void main1(String args[]) throws IOException {
2 FileInputStream fis = null;
3 ObjectInputStream oin = null;
4 try {
5 fis = new FileInputStream("c:/temp.out");
6 oin = new ObjectInputStream(fis);
7 TestClassSerial tcs = (TestClassSerial) oin.readObject();
8 System.out.println("version="+tcs.version);
9 }
10 finally {
11 if(fis != null) {
12 fis.close();
13 }
14 if(oin != null) {
15 oin.close();
16 }
17 }
18 }
執行結果為:100.
4、對象的序列化格式
TestClassSerial對象序列化輸出的
temp.out
文件,以
16
進制方式顯示,內容如下:
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64
這些二進制字節就是用來描述序列化以后的TestClassSerial對象的,我們注意到
TestSerial
類中只有兩個域:
1 public byte version = 100;
2 public byte count = 0;
都是
byte
型,理論上存儲這兩個域只需要
2
個
byte
,但是實際上
temp.out
占據空間為
51bytes
,也就是說除了數據以外,還包括了對序列化對象的其他描述。
5、Java
的序列化算法
序列化算法一般會按步驟做如下事情:
1、將對象實例相關的類的元數據輸出;
2、遞歸地輸出類的超類元數據描述直到不再有超類;
3、類元數據完了以后,開始從最頂層的超類開始輸出對象實例的實際數據值;
4、從上至下遞歸輸出實例的數據;
更多序例化事例及二進制字節含義參考文檔:http://my.oschina.net/god/blog/1291
posted @
2010-12-16 14:52 josson 閱讀(816) |
評論 (0) |
編輯 收藏
1、員工激勵
通過各種外部或內部的刺激,以激發員工的需要、動機、欲望,調動人的工作積極性,充分挖掘潛力,全力達到預期目標的過程。
2、激勵形式、方法:
廣義的分物質激勵和精神激勵(職務、榮譽、目標、信任、情感等)。

3、原則:
1)、精神激勵為主;
2)、只激勵該激勵的人;
3)、只激勵該激勵的事;
4)、激勵方法、手段因人而異,把握按需激勵;
5)、鼓勵公開競爭、和諧競爭;
4、案例:
1)、壓力非常大的時候,采用激勵手段 -- 目標激勵
2)、當前員工不開心,采用的手段 -- 先溝通,明確原因
3)、表現好的員工 -- 信任激勵,肯定
4)、推行新方法 -- 目標激勵,競賽
5、附:
馬斯洛需求層次理論(Maslow's hierarchy of needs),亦稱“基本需求層次理論”,是行為科學的理論之一,由美國心理學家亞伯拉罕·馬斯洛于1943年在《人類激勵理論》論文中所提出。
安全、生理需要屬于物質性價值需求;社會需要、尊重需要、自我實現屬于精神價值需求;
posted @
2010-12-09 16:17 josson 閱讀(377) |
評論 (0) |
編輯 收藏
解決沖突的法則
- 在不了解對方動機之前千萬不要表明自己的立場
- 準確把握自己的需求底線
- 解決沖突的最好辦法是談判
決策的法則
- 首先,以事實而后數據為依據,如果沒有,
- 以嚴密的邏輯推理為依據,如果沒有,
- 以民主評議,如果沒有,
- 以最終負責人來決斷
獎懲制度
- 在構建獎勵制度的同時不要忘記處罰制度的建設
- 物質與非物質的獎勵(以非物質的獎勵)
- 側重獎勵行為還是結果?
表揚要及時(3天為限)、有理有據、真誠。
表揚是最不花錢最辭舊的激勵手段,表揚是為下一個成功設立起點。
不要過度的物質獎勵,在這種方式的激勵下,員工永遠得不到激勵。
要注重精神上的獎勵,只有精神是永存的。
posted @
2010-11-24 10:31 josson 閱讀(365) |
評論 (0) |
編輯 收藏
垃圾收集的目的在于清除不再使用的對象,釋放那些不再使用的對象所占用的內存。GC兩種常用的方法是引用計數和對象引用遍歷,早期的jvm使用引用計數,現在大多數jvm采用對象引用遍歷。
1、對象引用計數:
當應用程序創建引用以及引用超出作用域(范圍)時,jvm必須適當增減引用數。當某對象的引用數為0時,對象便可以進行垃圾收集。
2、對象引用遍歷:
(1)、標記(marking)對象:從一組對象開始,沿著整個對象圖上的引用鏈,遞歸確定可到達的對象,GC將標記這些可到達的對象。如果某對象不能從這些根對象的一個(至少一個)到達,則表示它可被收集。
(2)、清除(sweeping)對象:GC刪除不可到達的對象,刪除時,有些GC只是簡單的掃描堆棧,刪除未標記的對象,并釋放它們的內存以生成新的對象。這種方法的問題在于內存會分成好多小段,而它們不足以用于新的對象,但是組合起來卻很大。因此,許多gc可以重新組織內存中的對象,并進行壓縮(compact),形成可利用的空間。
不一定要將所有的真話講出來,但你講的每一句真話必須是真話。(white
lie)
posted @
2010-07-28 14:37 josson 閱讀(248) |
評論 (0) |
編輯 收藏
最近一個項目主要涉及前端的交互優化,由于UED資源不足,所以一起做了一些前端的工作,
由于各瀏覽器的標準不一樣,如要兼容像ie6,7,8及firefox,樣式調整比較費事,現在css相關
的一些技巧分享一下,希望對大家有所幫助。
1、什么是css hack.
針對不同的瀏覽器去寫不同的CSS,讓它能夠同時兼容不同的瀏覽器,能在不同的瀏覽器中也
能得到我們想要的頁面效果,這種針對不同的瀏覽器寫不同的CSS code的過程,稱之為CSS hack。
通過下表中的hack
code就可以實現不同版本ie瀏覽器間的兼容:
hack code
|
ie6
|
ie7
|
firefox
|
_
|
√
|
×
|
×
|
*
|
√
|
√
|
×
|
!import
|
×
|
√
|
√
|
‘_’ : 只有ie6能識別_,如ie7,8下”width:100px; “的樣式是OK,但ie6不夠寬時,可以在”width:100px”后面增加一段”_width:105px;” 那么ie7,8不會解析_width:105px,但ie6會執行。
‘*’ : ie6,7都能識別*,但firefox不能識別;
‘!import’ : ie 6不能識別,ie7和ie8都能識別;
2、css調試工具
(1). ie8的調試工具,ie8下按F12能呼出開發人員開發工具,如下圖:

選中圖中的箭頭鼠標按鈕,在瀏覽器中選中需要優化的HTML對象,HTML窗口就會
定位到選中HTML對象的代碼上(如上圖左),則右窗口中則顯示當前對象的所有樣式,
通過對右窗口中的樣式調整,達到預期效果后,找到css文件的class,并作相同修
改。通過這個工具,修改樣式后所見即所得,確定樣式后再修改樣式文件。
(2). Firebug,firefox下可以通過Firebug工具,來定位HTML對象并調試該對象的樣式,如下圖:

posted @
2010-06-29 11:03 josson 閱讀(2194) |
評論 (0) |
編輯 收藏
事件 |
解說 |
一般事件 |
onclick |
鼠標點擊時觸發此事件 |
ondblclick |
鼠標雙擊時觸發此事件 |
onmousedown |
按下鼠標時觸發此事件 |
onmouseup |
鼠標按下后松開鼠標時觸發此事件 |
onmouseover |
當鼠標移動到某對象范圍的上方時觸發此事件 |
onmousemove |
鼠標移動時觸發此事件 |
onmouseout |
當鼠標離開某對象范圍時觸發此事件 |
onkeypress |
當鍵盤上的某個鍵被按下并且釋放時觸發此事件. |
onkeydown |
當鍵盤上某個按鍵被按下時觸發此事件 |
onkeyup |
當鍵盤上某個按鍵被按放開時觸發此事件 |
頁面相關事件 |
onabort |
圖片在下載時被用戶中斷 |
onbeforeunload |
當前頁面的內容將要被改變時觸發此事件 |
onerror |
出現錯誤時觸發此事件 |
onload |
頁面內容完成時觸發此事件 |
onmove |
瀏覽器的窗口被移動時觸發此事件 |
onresize |
當瀏覽器的窗口大小被改變時觸發此事件 |
onscroll |
瀏覽器的滾動條位置發生變化時觸發此事件 |
onstop |
瀏覽器的停止按鈕被按下時觸發此事件或者正在下載的文件被中斷 |
oncontextmenu |
當彈出右鍵上下文菜單時發生 |
onunload |
當前頁面將被改變時觸發此事件 |
表單相關事件 |
onblur |
當前元素失去焦點時觸發此事件 |
onchange |
當前元素失去焦點并且元素的內容發生改變而觸發此事件 |
onfocus |
當某個元素獲得焦點時觸發此事件 |
onreset |
當表單中RESET的屬性被激發時觸發此事件 |
onsubmit |
一個表單被遞交時觸發此事件 |
posted @
2010-04-11 13:05 josson 閱讀(154) |
評論 (0) |
編輯 收藏
1、讓用戶隨時了解系統的狀態;
2、系統應與真實世界相符合;
3、給予用戶控制權和自主權;
4、提倡一致性和標準化;
5、幫助用戶識別、診斷和修復錯誤;
6、預防錯誤;
7、依賴識別而不是記憶;
8、強調使用的靈活性及有效性;
9、最小化設計;
10、提供幫助及文檔;
posted @
2010-04-11 13:05 josson 閱讀(204) |
評論 (0) |
編輯 收藏
1、新建 archetype 項目(模板項目):
mvn archetype:genera -DgroupId=org.simple -DartifactId=simple -DarchetypeArtifactId=maven-archetype-archetype
2、修改主要模板文件:archetype-resources/pom.xml
1)修改 META-INF/maven/archetype.xml 中相關的 sources
2)安裝此項目:mvn install
3、根據模板項目創建新項目:
mvn archetype:generate
-DarchetypeGroupId=org.simple\
-DarchetypeArtifactId= simple \
-DarchetypeVersion=1.0-SNAPSHOT
【安裝私有庫】
1、復制 mylib-1.2.3.jar 到本地代碼庫
2、編寫 mylib-1.2.3.pom 文件:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mylib</groupId>
<artifactId>mylib</artifactId>
<version>1.2.3</version>
</project>
如果有依賴關系,可以將依賴關系描述在 pom 中
3、用Ant 來生成 jar 包和 pom 文件的 checksum 文件:
build.xml:
<project default="checksum">
<target name="checksum">
<checksum file="mylib-1.2.3.jar" algorithm="SHA" fileext=".sha1"/>
<checksum file="mylib-1.2.3.pom" algorithm="SHA" fileext=".sha1"/>
</target>
</project>
4、生成 mylib-1.2.3.jar.sha1 和 mylib-1.2.3.pom.sha1 文件
ant build.xml
【使用版本控制】
提交:mvn scm:checkin -Dmessage="Message"
檢出:mvn scm:checkout
更新:mvn scm:update
posted @
2010-04-11 13:02 josson 閱讀(874) |
評論 (0) |
編輯 收藏
作為一名開發者,通常會忽視系統可用性及用戶體驗。但系統的可用性和用戶體驗對于一個真正優秀的Web-based系統卻至關重要,因此,我們有必要花一些時間來了解和學習一下。
一、相關的概念:
用戶體驗,user experience(或稱ux/ue),指用戶訪問或使用一個產品/服務時的全部感受。具有主觀性,不同的用戶本身的知識、愛好、價值觀等會有不同的結果,因人而異。
可用性,指產品是否易學、使用是否有效果,以及通用性是否良好等。衡量一個產品的可用性,可以通過一些具體目標來評判,相對用戶體驗而言,比較客觀。考察產品可用性的目標可分為:
1、可行性,指產品使用的效果;
2、有效性,產品使用的工作效率;
3、安全性,指產品能否安全的使用,或稱為容錯性;
4、通用性,指產品是否具備良好的通用性;
5、易學性,指產品的是否容易上手,易操作;
6、易記性,指產品的操作方法簡單,易記性;
二、開發人員的特點
作為一名開發者,通常會對目標用戶的判斷有較大的偏差,往往高估實際用戶的操作能力和理解能力,忽視產品的易學性和易操作性。再者,作為技術人員,開發工作者通常重視功能實現,忽視產品界面、視覺外觀,不重視用戶體驗。
三、一些案例
1、iPhone的成功
iPhone的成功,產品的可用度及用戶體驗有者至關重要的作用。其產品的很多細節,都凝聚著apple公司的創新。如3.5吋屏幕上觸摸輸入,比較費輕且易出錯,但iphone在輸入過程中,會放大選中的字符,便于用戶確認,同時,作一些輸入校驗,進行容錯處理,避免用戶輸入錯誤字符引起的麻煩。
2、在線訂票、論壇注冊
再如個在線訂票系統,用戶興沖沖的跑上來想體驗一把,千辛萬苦輸入一大段信息,終于注冊成功,想下單的時候,即發現自己有的銀行卡不支持,試想此時用戶的心情會多么的糟糕。試想一下,如果在用戶注冊前,提示系統當前支持的銀行卡的話,用戶可以第一時間選擇其他的方式來實現自己的目的。
再談論壇的會員管理機制,網上這種案例也很多。用戶費了好大的勁完成注冊后,即告知新注冊用戶不能立即發言,很可能這個用戶就這樣失去了。
所以要做好一個產品,需要每位項目成員的投入,從用戶角度出度,解決用戶的實際問題。
posted @
2009-11-18 11:32 josson 閱讀(333) |
評論 (0) |
編輯 收藏
Codereivew是開發團隊中經常采用的,為提高代碼質量、提高編碼規范的一種手段。針對實際工作組織review過程中的一些想法、見解,作一下總結。
關于CodeReview的幾點作用:
1、提高團隊的編碼規范,培養良好的coding風格
旨在提高整個團隊的編碼規范程度,統一編碼風格。通過每次的codereivew,發現團隊成員在實際開發中的一些細節問題,如不良的編碼習慣、錯誤的調用方式等。通過多次的發現、解決問題,使大家都養成良好的編碼習慣。review的內容一般包括:
1)、異常、日志的處理;
2)、常量的定義及使用;
3)、字符串處理、BigDecimal.ZERO等;
4)、代碼的封裝,提高重用性;
5)、代碼注釋情況;
6)、javascript文件的抽取情況;
2、檢查業務邏輯
對項目實現的功能邏輯進行一次reivew,結合眾人發散思維,檢查業務邏輯是否有盲點或錯誤。通常需要參與review的成員能夠靜下心來深入地認真分析,比較耗費時間。
3、分享和培訓
每個項目的工作安排相對來說都是比較緊湊的,所以每個團隊成員在完成自己的開發任務完,沒有太多的時間去了解或熟悉其他成員的功能實現。但對于敏捷開發來說,每個功能模塊的開發者并不是固定的,根據項目需要,很有可能由非原開發人員來完成增值功能或重構,所以codereivew是一次不錯的培訓及分享機會,特別是對功能相對復雜的需求實現。可以讓團隊成員了解或熟悉基本的設計思想和相關的類定義,確保在今后接手這一塊工作時,可以更快的上手或找到最到最合適的人去了解更深層的邏輯。
關于reivew的方式:
1、集體review;
項目成員一起參與codereive,成本比較大,一般一個項目組織一次。比較適合開發經驗分享,以及新功能的實現介紹,利于其他成員了解、熟悉實現者的設計思路及代碼結構,在后續項目接手這些新功能時,更加從容。
2、TM組織若干開發經驗豐富的一起review;
3、分組、交叉review;
具有較好的靈活性,根據情況隨時找相關人員一起對已實現的代碼進行review,及時發現過程中問題并予以修正。比較適合分組\抱團開發,以2-3人為單位,對具體的功能模塊負責,一起分析、設計、編碼,每位成員對于功能邏輯都比較邏輯,對業務邏輯reivew有比較好的效果。
實際工作中,根據實際情況靈活選擇合適的review方式,不應拘于某種形式。review過程,應有明確的目的,具有針對性,而不是停留于表面,避免逐漸成為一種負擔,流于形式。另外,應對每次review結果,整理出一份問題列表,進行分析和總結,避免相同問題的重復出現。同時,也應按排相關人員跟進并解決問題。總之,通過codereivew這一手段,盡可能的在提交測試之前去發現代碼中存在的一些實際問題,從項目經歷中得到成長。
posted @
2009-09-20 16:50 josson 閱讀(421) |
評論 (0) |
編輯 收藏
因項目需要,實現系統對IE8的支持,安裝了ie8版本。安裝完后,發現一個奇怪問題,打開一個窗口(window.open方式)后,再打開時,新窗口的頁面顯示空白,無法加載其內容。關閉ie后,重新償亦是如此,第一次能打開,第二次就不行。無論是ie7模式,還是兼容模式。
網上搜了很多內容,都沒有找相應的解決方案。后來償試了一下,ie設置重置(工具-Internet選項-高級-重置),刪除所有個性化設置,完成后,重試后該問題不再出現,窗口能正常打開。回想,可能是裝完ie后,ie設置向導中做了某些不當的設置有關,但具體是哪項尚不得而知。
posted @
2009-09-12 15:01 josson 閱讀(4054) |
評論 (2) |
編輯 收藏
在原網頁窗口高度根據內容自適應的基礎上,做了一些調整:
1、解決窗口底部靠近任務欄時,
window.resizeBy 不能調整窗口高度問題;
1、增加寬度自適功能(注:只針對寬度不足,進行擴展的情況;無法調整窗口寬度比實際內容寬的情況)
Ext.util.ResizeWin = function() {
try {
var sh = document.documentElement.scrollHeight
|| document.body.scrollHeight;
var ch = document.documentElement.clientHeight
|| document.body.clientHeight;
var sw = document.documentElement.scrollWidth
|| document.body.scrollWidth
var cw = document.documentElement.clientWidth
|| document.body.scrollWidth;
var xHeight = 55;//任務欄高度(double).
var statHeigth = 30;//狀態欄高度
var maxHeight = window.screen.height - xHeight; //最大可顯示網頁高度
var wHeight = window.screenTop + sh + statHeigth;
if(wHeight > maxHeight){
//窗口位置過底時,向上移動若干象素,使窗口狀態欄在任務欄上面.
var newTop = (window.screenTop - xHeight) + (maxHeight - wHeight);
if(newTop < 0) newTop = 0;
window.moveTo(window.screenLeft, newTop);
}
//寬度調整時,實際內容不夠寬可以適用,過寬無法調整.
window.resizeBy((sw-cw),(sh-ch));
}catch (e){}
};
以下從網上收集的一些相關資料:
1、關于網頁窗口高、寬示意圖:
2、更多屬性:
網頁可見區域寬:document.body.clientWidth
網頁可見區域高:document.body.clientHeight
網頁可見區域寬:document.body.offsetWidth (包括邊線的寬)
網頁可見區域高:document.body.offsetHeight (包括邊線的寬)
網頁正文全文寬:document.body.scrollWidth
網頁正文全文高:document.body.scrollHeight
網頁被卷去的高:document.body.scrollTop
網頁被卷去的左:document.body.scrollLeft
網頁正文部分上:window.screenTop
網頁正文部分左:window.screenLeft
屏幕分辨率的高:window.screen.height
屏幕分辨率的寬:window.screen.width
屏幕可用工作區高度:window.screen.availHeight
屏幕可用工作區寬度:window.screen.availWidth
HTML精確定位:scrollLeft,scrollWidth,clientWidth,offsetWidth
scrollHeight: 獲取對象的滾動高度。
scrollLeft:設置或獲取位于對象左邊界和窗口中目前可見內容的最左端之間的距離
scrollTop:設置或獲取位于對象最頂端和窗口中可見內容的最頂端之間的距離
scrollWidth:獲取對象的滾動寬度
offsetHeight:獲取對象相對于版面或由父坐標 offsetParent 屬性指定的父坐標的高度
offsetLeft:獲取對象相對于版面或由 offsetParent 屬性指定的父坐標的計算左側位置
offsetTop:獲取對象相對于版面或由 offsetTop 屬性指定的父坐標的計算頂端位置
event.clientX 相對文檔的水平座標
event.clientY 相對文檔的垂直座標
event.offsetX 相對容器的水平坐標
event.offsetY 相對容器的垂直坐標
document.documentElement.scrollTop 垂直方向滾動的值
event.clientX+document.documentElement.scrollTop 相對文檔的水平座標+垂直方向滾動的量
IE,FireFox 差異如下:
IE6.0、FF1.06+:
clientWidth = width + padding
clientHeight = height + padding
offsetWidth = width + padding + border
offsetHeight = height + padding + border
IE5.0/5.5:
clientWidth = width - border
clientHeight = height - border
offsetWidth = width
offsetHeight = height
(需要提一下:CSS中的margin屬性,與clientWidth、offsetWidth、clientHeight、offsetHeight均無關)
網頁可見區域寬: document.body.clientWidth
網頁可見區域高: document.body.clientHeight
網頁可見區域寬: document.body.offsetWidth (包括邊線的寬)
網頁可見區域高: document.body.offsetHeight (包括邊線的高)
網頁正文全文寬: document.body.scrollWidth
網頁正文全文高: document.body.scrollHeight
網頁被卷去的高: document.body.scrollTop
網頁被卷去的左: document.body.scrollLeft
網頁正文部分上: window.screenTop
網頁正文部分左: window.screenLeft
屏幕分辨率的高: window.screen.height
屏幕分辨率的寬: window.screen.width
屏幕可用工作區高度: window.screen.availHeight
屏幕可用工作區寬度: window.screen.availWidt
posted @
2009-09-05 18:15 josson 閱讀(444) |
評論 (0) |
編輯 收藏
1、ssh 登錄linux時,報: ssh_exchange_identification: Connection closed by remote host
google了好一陣,才找到線索。主要由于我前晚寫shell腳本調試的時候,誤將一些系統文件的宿主為新用戶了。后來新的會話怎么都登錄不上去了,好在還有一個root登錄的會話,找到/var/empty/sshd,修改宿主及權限。
chown -R root:root /var/empty/sshd
chmod 700 /var/empty/sshd
2、su 切換用戶,輸入密碼總是提示:密碼不正確。
也是權限問題,root切到其他賬號時沒有問題;其他賬號之間切換就是不行,密碼輸入也正確。后來其到/bin/su 文件的權限不正確,調整如下解決問題:
-rwsr-xr-x 1 root root 61144 Jul 30 2007 /bin/su
posted @
2009-08-13 18:34 josson 閱讀(197) |
評論 (0) |
編輯 收藏
一般業務系統中總會存在一些基礎數據,在其他的業務單據中會被套引用。因此,系統必須保證這些被業務單據引用的基礎數據不能任意的刪除。最常見的做法就是,在刪除基礎數據時,預先校驗該類數據是否在相關業務表中存在,若不存在才允許用戶刪除,否則給用戶以提示。
但這樣的處理方法,有些缺點,就是需要編碼對每個業務類提供查詢方法,或在刪除邏輯中增加判斷邏輯。因此,每次引用關系變化,增加或減少時免不了要修改原來的邏輯,時間越長,系統的維護成本就越來越高了。因此,有必要對系統進行重構,將這類的處理邏輯進行抽象,單獨封裝成一個服務,當引用關系有變更時,不用再修改原有邏輯,通過配置就可以完成變更。
通用引用關系查詢服務,主要就是通過db表或xml配置文件,對系統中每個基礎數據有引用的所有關系進行定義,定義屬性主要是引用的表及字段名稱。查詢時,從配置文件中讀取指定類別的引用關系,并逐一查詢這些表中的記錄,以確定數據是否被引用。這種處理方法的優點為,易擴展、可維護性強,引用關系變更時,僅通過維護配置文件,不必進行編碼,就能實現,這樣能大大的提高系統的穩定性。
xml配置文件如下:
<rule bizName='product' desc="產品關聯項定義">
<item>
<refTable>sale_item</refTable>
<refField>product_id</refField>
<!-- 用于查詢條件的擴展,允許為空 -->
<extCondition>CORP_ID = #corpId#</extCondition>
</item>
<item>
<refTable>sale_order_item</refTable>
<refField>product_id</refField>
<extCondition>CORP_ID = #corpId#</extCondition>
</item>
</rule>
<rule bizName='customer' desc="客戶關聯項定義">
<item>
<refTable>sale_order</refTable>
<refField>cust_id</refField>
<extCondition>CORP_ID = #corpId#</extCondition>
</item>
<item>
<refTable>sale_bill</refTable>
<refField>cust_id</refField>
<extCondition></extCondition>
</item>
... ...
</rule>
通用業務引用查詢類代碼片段如下:
public class BizReferenceService implements IBizReferenceService {
private static Map<String,List<BizReferenceRule>> ruleMaps;
private static final String PATTERN = "#[\\w]+#";
private static final String CFG_FILE = "bizReferenceRule.xml";
... ...
/**
* 查詢指定業務數據是否被其他業務表關聯依賴.
* @param bizName 關聯業務名稱
* @param bizId 關聯業務ID.
* @param extParam 擴展條件
* @return true 被關聯/false 未被關聯.
*/
public boolean isBizReference(String bizName,String bizId,Map<String,Object>extParam) throws ServiceException {
Assert.notNull(bizName, "業務名稱不能為空,bizName is NULL。");
Assert.notNull(bizId, "記錄ID不能為空,bizId is NULL。");
try {
//逐個檢查依賴項是否有數據關聯.
List<BizReferenceRule> rules = getBizRelationRule(bizName);
for(BizReferenceRule rule : rules){
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("select count(*) from ").append(rule.getRelTable()).append(" where ")
.append(rule.getRelField()).append("='").append(bizId).append("' ");
String extConditon = rule.getExtCondition();
if(StringUtil.isNotBlank(extConditon)){
initTenantParam(extParam);
sqlBuilder.append(" and ").append(getExtParamSql(extConditon,extParam));
}
logger.debug(sqlBuilder);
int nCount = bizReferenceDao.getBizRelationCount(sqlBuilder.toString());
if (nCount != 0) return true;
}
return false;
}
catch(Exception ex){
logger.error("調用業務關聯服務錯誤。"+bizName+",bizId:"+bizId+",extParam"+LogUtil.parserBean(extParam),ex);
throw new ServiceException("調用業務關聯服務錯誤。");
}
}
/**
* 組裝擴展查詢條件的sql
* @param condition
* @param extParam
* @return
* @throws Exception
*/
private String getExtParamSql(String condition,Map<String,Object>extParam) throws Exception {
List<String> paramList = parseDyncParam(condition);
for(String param : paramList){
String simpleParam = simpleName(param);
if(!extParam.containsKey(simpleParam)){
throw new ServiceException("動態參數值未設置! param:"+param+",extParam:"+LogUtil.parserBean(extParam));
}
condition = condition.replaceAll(param, "'"+String.valueOf(extParam.get(simpleParam))+"'");
}
return condition;
}
/**
* 解析擴展查詢條件中的動態參數名.
* @param condition
* @return
* @throws Exception
*/
private List<String> parseDyncParam(String condition) throws Exception {
PatternCompiler compiler = new Perl5Compiler();
PatternMatcher matcher = new Perl5Matcher();
MatchResult result = null;
PatternMatcherInput input = null;
List<String> paramList = new ArrayList<String>();
input = new PatternMatcherInput(condition);
Pattern pattern = compiler.compile(PATTERN,Perl5Compiler.CASE_INSENSITIVE_MASK);
while (matcher.contains(input, pattern)){
result = matcher.getMatch();
input.setBeginOffset(result.length());
paramList.add(result.group(0));
}
return paramList;
}
/**
* 獲取業務關聯查詢規則.
*/
private List<BizReferenceRule> getBizRelationRule(String bizName){
Assert.notNull(bizName, "業務名稱不能為空,bizName is NULL。");
//配置定義未加載到內存時,讀取配置文件
if(ruleMaps == null){
parseRuleConfig();
if(ruleMaps == null) return null;
}
return ruleMaps.get(bizName);
}
/**
* 讀取業務關聯規則配置文件
*/
@SuppressWarnings("unchecked")
private synchronized void parseRuleConfig(){
if(ruleMaps != null){
return;
}
//解析業務引用定義文件.

}
/**
* 讀取Xml文檔
* @return
*/
private Document getXmlDocument(){
InputStream is = null;
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
is = loader.getResourceAsStream(CFG_FILE);
SAXBuilder sb = new SAXBuilder();
return sb.build(new BufferedInputStream(is));
}
catch(Exception ex) {
logger.error("讀取配置文件錯誤. file:"+CFG_FILE, ex);
return null;
}
finally {
try {
if(is != null){
is.close();
is = null;
}
}
catch(Exception ex) {
logger.error(ex);
}
}
}

}
其他的一些可選處理方法:
b. 在客戶表增加引用計數字段;
需額外維護引用計數字段,在引用的業務邏輯增加或刪除記錄時,需對該字段的數值進行更新。適用于需要直接查詢記錄被引用次數的場景,但在集群環境下,需注意并發問題。
posted @
2009-07-14 14:42 josson 閱讀(385) |
評論 (0) |
編輯 收藏
關于瀏覽器的clientHeight、offsetHeight和scrollHeight
在IE、FireFox、Netscape等不同的瀏覽器里,對于document.body 的 clientHeight、offsetHeight 和 scrollHeight 有著不同的含義,比較容易搞混,現整理一下相關的內容:
clientHeight:在上述瀏覽器中, clientHeight 的含義是一致的,定義為網頁內容可視區域的高度,即在瀏覽器中可以看到網頁內容的高度,通常是工具條以下到狀態欄以上的整個區域高度,與具體的網頁頁面內容無關。可以理解為,
在屏幕上通過瀏覽器窗口所能看到網頁內容的高度。
offsetHeight:關于offsetHeight,ie和firefox等不同瀏覽中意義有所不同,需要加以區別。在ie中,offsetHeight 的取值為 clientHeight加上滾動條及邊框的高度;而firefox、netscape中,其取值為是實際網頁內容的高度,可能會小于clientHeight。
scrollHeight:scrollHeight都表示瀏覽器中網頁內容的高度,但稍有區別。在ie里為實際網頁內容的高度,可以小于 clientHeight;在firefox 中為網頁內容高度,最小值等于 clientHeight,即網頁實際內容比clientHeight時,取clientHeight。
clientWidth、offsetWidth 和 scrollWidth 的含義與上述內容雷同,不過是高度變成寬度而已。
若希望clientHeight、offsetHeight和scrollHeight三個屬性能取值一致的話,可以通過設置DOCTYPE,啟用不同的解析器,如:<!DOCTYPE HTML PUBLIC "DTD XHTML 1.0 Transitional">,設置DOCTYPE后,這三個屬性都表示實際網頁內容的高度。
通過以下HTML代碼,可以了解一下這三個屬性的含義:
<!DOCTYPE HTML PUBLIC "DTD XHTML 1.0 Transitional"> //設置DOCTYPE
<HTML>
<HEAD>
<TITLE> 測試。 </TITLE>
</HEAD>
<script type='text/javascript'>
window.onload = function(){
var ch = document.body.clientHeight;
var sh = document.body.offsetHeight;
var ssh = document.body.scrollHeight;
alert('clientHeight:'+ch+'; offsetHeight:'+sh+"; scrollHeight:"+ssh);
}
</script>
<BODY style='margin:0px'>
<div style='background-color:#ccc; height:400px; padding:0px'>
text
</div>
</BODY>
</HTML>
根據頁面內容調整窗口高度的方法:
Ext.util.ResizeWin = function() {
try {
var sh = document.documentElement.scrollHeight
|| document.body.scrollHeight;
var ch = document.documentElement.clientHeight
|| document.body.clientHeight;
window.resizeBy(0,(sh-ch));
}catch (e){}
};
posted @
2009-06-14 16:48 josson 閱讀(1495) |
評論 (0) |
編輯 收藏
我們通常依賴單元測試工具Luntbuild,來發現代碼中有許多隱藏的錯誤或不良的編碼,然后再去修正。這樣從發現問題,到解決問題花費很多功夫。其實我們可以利用一些java代碼分析工具,來及時發現相關的問題。如findbugs,luntbuild就是集成了findbugs插件來發現一些代碼上的問題。
findbugs 當前版本為:1.3.9,其下載地址如下(包括eclipse插件):
findbugs :http://findbugs.sourceforge.net/index.html
findbugs for eclipse : http://findbugs.sourceforge.net/downloads.html
documents: http://findbugs.sourceforge.net/manual/
插件安裝比較簡單,將findbugs for eclipse 插件文件(zip)下載后,直接解壓至$eclipse.home$/plugins/目錄下,重啟eclipse即可使用。你可以通過查看:(eclipse 3.4) about ecliplse platform -> plug-ins details 中找到findbugs 插件安裝信息。
Findbugs 的使用:
在Package Explorer或Navigator視圖中,選中你的Java項目,右鍵,可以看到“Find Bugs”菜單項,子菜單項里有“Find Bugs”和“Clear Bug Markers”等項。點擊Find Bugs 后,開始分析項目中隱藏的代碼問題,發現的問題會在相應的代碼行上進行標記,或者在Bug Explorer中顯示所有的問題(findbug視圖,window -> show view -> others 可以找到Bug Explorer.) 我們就可以根據findbugs發現的問題,進行逐一解決,提高代碼質量。
Findbugs 的一些配置說明:
FindBugs是一個基于“Bug Patterns”進行分析并找出Java程序中隱藏的Bugs。打開 Window -> preferences ,對findbugs 的分析規則進行定義,如圖:
posted @
2009-06-13 23:55 josson 閱讀(1239) |
評論 (0) |
編輯 收藏