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

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

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

    張昊

    J-Hi(http://www.j-hi.net)

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      45 Posts :: 1 Stories :: 110 Comments :: 0 Trackbacks

    #

    實現方式
    1、在struts.xml或xwork.xml加如下配置信息
            <global-results>
                
                
    <result name="auto">/${proxy.config.packageName}/${proxy.method}.jsp</result>           
            
    </global-results>

    2、在BaseAction類中加入proxy的方法實現
          private ActionProxy proxy;
       
        public ActionProxy getProxy(){
            if(proxy  == null)
                proxy = ActionContext.getContext().getActionInvocation().getProxy();
            return proxy;
        }

    3、做一個JSP文件,文件名一定要與action的方法名相同,列如:a.jap那么action的方法的寫法
        public String a() throws Exception{
            
            
    return AUTO;
        }

    4、在某個Jsp頁面中調于這個無配置actoin的寫法
        actionName!a.action

    分析
       ActionProxy類是struts2或webwork提供的一個action代理類,它的作用是它的作用是記錄當前這個action的對象、action的名稱、配置信息及該action所屬的包名等信息。該接口的聲明如下
    public interface ActionProxy {

        
    /**
         * 
    @return the Action instance for this Proxy
         
    */
        Object getAction();

        
    /**
         * 
    @return the alias name this ActionProxy is mapped to
         
    */
        String getActionName();

        
    /**
         * 
    @return the ActionConfig this ActionProxy is built from
         
    */
        ActionConfig getConfig();

        
    /**
         * Sets whether this ActionProxy should also execute the Result after executing the Action
         *
         * 
    @param executeResult
         
    */
        
    void setExecuteResult(boolean executeResult);

        
    /**
         * 
    @return the status of whether the ActionProxy is set to execute the Result after the Action is executed
         
    */
        
    boolean getExecuteResult();

        
    /**
         * 
    @return the ActionInvocation associated with this ActionProxy
         
    */
        ActionInvocation getInvocation();

        
    /**
         * 
    @return the namespace the ActionConfig for this ActionProxy is mapped to
         
    */
        String getNamespace();

        
    /**
         * Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext
         * ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal.
         *
         * 
    @return the result code returned from executing the ActionInvocation
         * 
    @throws Exception
         * 
    @see ActionInvocation
         
    */
        String execute() 
    throws Exception;

        
    /**
         * Sets the method to execute for the action invocation. If no method is specified, the method provided by
         * in the action's configuration will be used.
         *
         * 
    @param method the string name of the method to invoke
         
    */
        
    void setMethod(String method);

        
    /**
         * Returns the method to execute, or null if no method has been specified (meaning "execute" will be invoked)
         
    */
        String getMethod();
    }
     
       J-Hi借用了這個代理類,在action的基類也就是BaseAction中添加了對該類實例的引用,從而實體全局配置
           <result name="auto">/${proxy.config.packageName}/${proxy.method}.jsp</result> 
       其中${proxy.config.packageName}用來指定當前action所屬的包名,例如,"testjs"就是配置文件的包名
    <xwork>
        
    <package name="testjs" extends="hi" >
          
    <action name="materialList"
                class
    ="org.hi.testjs.action.webwork.MaterialListAction">
                
    <result name="success">/testjs/MaterialList.jsp</result>
                
    <interceptor-ref name="modelParamsStack" />
            
    </action>
    .
    </xwork>
      ${proxy.method}是指調用該action的方法名
      name="auto" 是我們特意為這樣無配置的actoin起了一個特定的名字,也就是說 
          

        public String a() throws Exception{
           
    return "auto";     
            或
            
    return AUTO;
        }
      效果是一樣的
     
      我們特意將這段result的配置放在了
    <global-results>中原因是省去寫配置文件,只要是return "auto";就會調用這個結果。那么它的結果是什么呢?對,是一個JSP,也就是說你通過actionName!method.action后,系統會自動執行這個方法,并自動調用這個aciton所屬包名下的與方法名相同的jsp文件。例如配置文件的包名為"testjs",actionName為"materialList",對應的class為"org.hi.testjs.action.webwork.MaterialListAction",你在這個action類中增加了一個a(),想通過調用該方法實現無配置調用jsp,那么你就應該將這個jsp文件放到web/testjs(與包名相同)目錄下,并且該jsp的文件名為a.jsp(與方法名相同)。調用這個action方法的寫法如下:materialList!a.action。OK,大工告成??!

    技巧
       為了適應不同人對action的開發習慣,J-Hi對struts2與webwork的生成方式是不同的。struts2是所有的操作都放在一個Action類中通過方法調用,而webwork是每個一操作一個Action類。兩種方式均有優勢也優有不足之處,大家在使用時全憑自己的習慣就好。我們之所以實現無配置,主要是考慮到J-Hi它不只是一個開發管理系統的平臺,也應該可以做網站或電子商務前端的開發。我們知道對于后臺管理系統主要考慮的是系統安全性(頁面的布局與樣式風格要統一),而網站或電子商務前端恰好相反,它追求的是安全不是問題因為它歡迎更多的瀏覽者不需要對每個操作都做權限控制(頁面的風格也五花八門,炫、酷不規則是這類系統的特點)。因此提供了無配置文件的方式,以滿足這類需求(當然純頁面還是要由美工來完成,無規則平臺的生成器是無法勝任該工作的)。由此而帶來的另一個問題是,平臺已經生成了很多aciton的功能,如何讓前臺與后臺共用這些已生成的action類呢?下面我們以struts2為例
       在BaseAction中有一個protected String returnCommand()方法,該方法是確定返回的結果的名字
        protected String returnCommand(String message){
            String viewMode 
    = HiConfigHolder.getViewMode();
            
            
    if(viewMode.equals("dwz")){                   
                
    if ((ajax == null || !ajax.trim().equals("1")) && message == null)
                    
    return SUCCESS;
                
    if(message == null)
                    
    return ajaxForwardSuccess(I18NUtil.getString("操作成功"));  //如果是dwz版就返回一個json對象的字符串
                
    else
                    
    return ajaxForwardError(message);
            }
            
            
    return SUCCESS;  //如果是經典版就返回success字符串
        }
      如果你想在前臺調用平臺已生成的action,而跳過權限控制,就可以通過無配置文件這種方式來實現,解決方案為,你在要做無配置的action類中覆蓋BaseAction的retunCommand()方法,覆蓋的實現方法如下:
        protected String returnCommand() {
            
            
    if(this.getRequest().getRequestURI().indexOf("!">0)   //如果在URL中包含!就說明是無配置的,它就會返回auto
                
    return "auto";
            
            
    return super.returnCommand();              //否則就走BaseAction也就是父類的retunCommand()方法
            }

      例如struts的action配置文件如下
    <struts>
        
    <package name="testjs" extends="hi" >
          
    <action name="material"
                
    class="org.hi.testjs.action.struts.MaterialAction">
                
    <interceptor-ref name="modelParamsStack" />
            
    </action>
    .
    </struts>
      平臺生成的MaterialAction類會有一個materialList(),你想在前臺調用而忽略權限,就可以寫成material!materialList.action,就可以了


    posted @ 2011-04-28 23:03 張昊 閱讀(1920) | 評論 (0)編輯 收藏

    安裝插件后的eclipse啟動不能創建hi項目 或者點完成時 很快就回到當前頁面。

    eclipse   創建 eclipse.exe 的快捷方式

    在快捷方式右鍵查看屬性 在目標后面加上 -clean 

    雙擊快捷方式啟動eclipse

    ok

    啟動tomcat時報錯

    把默認的刪除 

    新建服務器

    點完成 就ok



                                       注:該文檔由J-Hi愛好者"羅天文"提供,他的QQ號為610817750,歡迎大家與他在技術上多多交流

    posted @ 2011-04-27 01:29 張昊 閱讀(2849) | 評論 (7)編輯 收藏

    一、什么是代碼高手?你怎么證明自己是代碼高手?

    知道許多代碼技巧、JS炫彩技巧的人大有人在。你知道多少個.net函數,這一點都沒有意義。你知道多少個新鮮IT名詞,多少技術介紹,這也沒有意義。做,真正做一個原型,做一個項目,解決你手頭棘手的問題,這才有意義。

    1、快速準確的理解別人說的-〉

    2、快速的開發,還準確的反映了別人的需求-〉

    3、穩定,最少出BUG-〉

    4、高性能,10萬條記錄你能頂住,1000萬條記錄你能頂住嗎?這就是技術功底的考驗

    5、這還不夠,你的代碼是否能讓別人快速的理解了

    6、你的代碼是否能比較容易的接受不同客戶的需求差異

    這都是處處要你的分析功底、架構功底、編碼功底。

    二、怎么煉成高手?

    1、閱讀優秀的開源源代碼。先找代碼量不大的。要徹底的閱讀,剖析清楚有多少個類,這些類的關系。為什么要設計這樣的類架構,為什么要這樣設計接口。這些思考相當有深度。

    2、根據你的需求,把開源源代碼進行修改。因為開源源代碼是渾然一體,你加的功能是否很好和現有代碼融合。這相當考驗功底。

    3、 讀書,誰發明的這個東西就讀誰的書。如想學 SQLSERVER,就一定要讀SQLSERVER開發經理或技術小組寫的書。別人寫的書都會有歧義。要讀透,反復閱讀它的設計原理。不要只學會使用。比 如說SQLSERVER,寫SQL和SP就是懂SQLSERVER?我們一定要明白到SQLSERVER的數據頁面是如何組織的,為什么要這樣組織,它是 怎樣被載入內存中,它又是怎樣回寫到物理設備上。我們要到這個深度。否則,你只能是知道個皮毛,平時看是高手,一到真正難關立馬歇菜。

    如果你學的技術還不能幫助你解決你目前手頭的問題,說明你還學的不到位。

    4、 找到你的師傅。一個人的成長,很難是自己一個人苦苦學習摸索修煉。這樣提升很慢。你如果想快速發展,你必須找到你在這家公司中的引路人。他可能是你的入職 指引人,也可能是別人。你一定要好好觀察,看中了就一定要積極聯系上他緊緊的跟隨著他,平時多請教多觀察他的思考方式做事方式。

    5、給 自己樹立一個信念:我要在X年中成為公司所有人公認的技術高手。我要在X年終成為中國軟件業一流的程序員。必須設立目標,而且時時刻刻為這個目標奮斗,堅 持每天閱讀、思考、開發、修改代碼達到13-16個小時以上。有一個故事講的就是每件事要想做專業必須要經過1萬個小時的反復練習才能成功。對,我說的就 是這個意思。不瘋魔不成活。



    一個成功的產品的誕生是多么的曲折與艱難,中間會經歷多少商業競爭機緣巧合,也會浮現多少獨當一面的代碼英雄。
    一個人有沒有可能成為軟件高手,他是有一種說不清的氣質的,你知道那就是程序員精神,他是與眾不同的,你能明顯感覺的到。

    作為我個人,在技術上我是一直關注數據架構層、Java架構層、前端架構、和大型Web應用與研發。在業務上,我一直關注電子商務、互聯網生活服務/互聯網營銷/互聯網客戶關系社區、Web前端技術。 最后一句話:

    美到極致是瘋狂。希望大家在平時工作中開發每一個產品時,都能暗下決心:It's My Baby!

    對,它就是你創造的孩子,你要用心去雕琢它呵護它。?


                                        全文轉至張慧華的博文URL:美到極致是瘋狂
    posted @ 2011-04-25 22:54 張昊 閱讀(18305) | 評論 (5)編輯 收藏

        明天J-Hi for DWZ bate版就要發布了,心里很激動,感觸良多......
    J-Hi在沒集成DWZ之前頁面端一直是它的軟肋,之所以沒有對富客戶端的支持原因有三
       1)我自身的原因,始終認為過多的引入ajax會降低開發速度,增大了使用者的學習曲線,增大了開發工作量
       2)團隊內部原因,J-Hi核心團隊成員對js與頁面美工技術能力還很簿弱
       3)我一直沒有找到中國人自已做的設計優秀,而又不影響開發人員針對JSP的開發習慣的開源架構做集成
    有一天一個朋友(張國勇)給我推薦了DWZ,簡單的分析了一下它的運行原理,我一下子就喜歡上了它,原因如下:
       1)它是國產的,盡管內核仍采用的是JQuery,但在使用時基本上可以脫離JQuery,也就是說你可以基本的認為JQuery是一個黑箱
       2)它足夠輕量,內核很小加上JQuery壓縮后只有160K左右
       3) 它尊重開發人員的開發習慣,js部分的處理全部交給DWZ,只要在html中指定相應的class就可以。也就是說除非業務必須否則開發人員根本不用寫js代碼
       4)頁面與局布是通過JSP渲染,而不象ext等其它的富客戶端框架純js實現,這樣更方便開發人員對頁面的控制

        后來通過網絡我認識了DWZ開發團隊核心成員張慧華,給我的第一印象他是待人謙和,不善言談的人。我到現在還清楚的記得我們第一次見面的情景,我在我們約好的公交車站等他,他抱著他的女兒來接我,心情平靜而又談吐隨意。本來這一切都很平常,然而通過后面的聊天,卻讓我對他,對他的心態與人格肅然起敬。
               我寒喧的問他“這是你女兒?”
               他說“是,這是我大女兒”
               我開玩笑的說“你真行,難不成來有一個小女兒?”
               他說“對”
               我說“你的小女兒在那里,我怎么沒看到呀?”
               他說“住院了”
               我對“孩子怎么了?得了什么???”當時我就在想每個為人父母的,孩子病了都會很難過
               他說“小女兒得了白血病”
        我聽到這里,一下驚呆了,不自禁的看了他一眼,他還是那樣心態平和。如此的大事在我和他聊天過程,他始終沒有情緒上的變化,反而是我心情跟著他的談話起伏不定。當時我在想,如果這事放在我的身上,我早就象熱鍋上的螞蟻,焦躁不安了。這是怎樣一個人,怎樣的一個心態???如此淡定,達觀的人生態度,我還第一次見到,對他充滿敬意。
        隨著后來我們接觸的越來越多,我看到他正像他說的一樣“我盡我最大的能力去做我該做的事情,無論結果如何起碼問心無愧,不會后悔”--每周都往返于醫院、家里和公司之間,有時還要在醫院通宵的護理他的小女兒(因為要化療)--我看他真是辛苦,看著他這樣我都覺得疲憊,我想這種疲憊不只是肉體的也許心理的更大吧!然后我卻從來沒有聽到他的一句怨言,甚至是述苦的話。我也從未安慰過他,我想如此堅強的人我的安慰是多余的。
        后來他答應幫助我做J-Hi對DWZ的融合工作,在工作過程中我更是對他超強的精力與嫻熟的技術佩服不已,因為我負閑在家,所以每天都在凌晨兩點多睡覺九點多起床,因為我們總是在QQ上實時聯絡,而他每天都是凌晨一點才會休息,他的公司與家離的很遠,每天六點半就要起床,如此精力充沛的人我還真是頭一次見到。他是一個工作狂,對技術有狂熱的興趣。我自認為自己對技術是一個近乎偏執的狂人,而與他相比,看來我把自己高估了。
       
        明天J-Hi for DWZ bate版就要發布了,我對曾經幫助過我的人充滿感激,特別是張慧華這里面不只是感激更多是敬意。我很慶幸有一個團隊,有大家的幫助,更有象張慧華這樣的朋友!

    posted @ 2011-04-25 02:30 張昊 閱讀(4977) | 評論 (16)編輯 收藏

    Svn簡介

    Subversion簡稱svn是一個自由/開源的版本控制系統。也就是說,在Subversion管理下,文件和目錄可以超越時空。也就是Subversion允許你數據恢復到早期版本,或者是檢查數據修改的歷史。正因為如此,許多人將版本控制系統當作一種神奇的“時間機器”。

    Subversion的版本庫可以通過網絡訪問,從而使用戶可以在不同的電腦上進行操作。從某種程度上來說,允許用戶在各自的空間里修改和管理同一組數據可以促進團隊協作。因為修改不再是單線進行,開發速度會更快。此外,由于所有的工作都已版本化,也就不必擔心由于錯誤的更改而影響軟件質量如果出現不正確的更改,只要撤銷那一次更改操作即可。

    某些版本控制系統本身也是軟件配置管理(SCM)系統,這種系統經過精巧的設計,專門用來管理源代碼樹,并且具備許多與軟件開發有關的特性比如,對編程語言的支持,或者提供程序構建工具。不過Subversion并不是這樣的系統。它是一個通用系統,可以管理任何類型的文件集。對你來說,這些文件這可能是源程序而對別人,則可能是一個貨物清單或者是數字電影。

    一個典型的客戶/服務器系統:

    Subversion版本庫的特別之處在于,它會記錄每一次改變:每個文件的改變,甚至是目錄樹本身的改變,例如文件和目錄的添加、刪除和重新組織。

    一般情況下,客戶端從版本庫中獲取的數據是文件系統樹中的最新數據。但是客戶端也具備查看文件系統樹以前任何一個狀態的能力。舉個例子,客戶端有時會對一些歷史性問題感興趣,比如“上星期三時的目錄結構是什么樣的?”或者“誰最后一個修改了這個文件,都修改了什么?”這些都是版本控制系統的核心問題:設計用來記錄和跟蹤數據變化的系統。

    服務器端軟件安裝

    這里選擇用VisualSVN-Server-2.1.7.msi搭建svn版本庫服務器。

    下載地址:http://www.visualsvn.com/server/download/

    一直默認進行安裝:

    選擇:VisualSVN Server and management Console

    D:

    (Location:指的是軟件安裝的位置。Repositories:是需要svn控制的源碼存放的位置。端口保持默認:443)

    (Anthentication:身份驗證模式,這里注意,如果選用第二個User Windows authentication,可能需要域環境。我選用的第一個。)

    服務器配置運行

    新建用戶

    右擊左側的Users,選擇新建---User ,新建用戶

    D:

    新建repository(版本庫)

    選中 Repositories,在右側的空白區域,選擇新建---Repository,輸入名字e-test,這樣就創建了一個項目

    D:

    url是:https://sihao-PC/svn/e-test

    sihao-PC是我的電腦名,e-test是我的項目名。中間的svn是默認就有的,注意由于我沒有加入域,所以在客戶端獲取的時候要把電腦名換成它的ip地址

    賦予用戶權限

    右擊e-test,所有任務--Manage Security 或者properties

    新建的用戶添加進去并賦值權限,如下圖:

    D:

    這樣就完成了服務器所有內容。

    (參考文檔:http://hi.baidu.com/sygwin/blog/item/7f2f1217168f0d144a90a793.html)

    客戶端軟件介紹

    客戶端可以選擇TortoiseSVN-1.6.15.21042-win32-svn-1.6.16.msi

    下載地址:http://tortoisesvn.net/downloads.html

    也可以用eclipsesvn插件:Subclipse

    下載地址:http://subclipse.tigris.org/

    本文主要介紹用eclipse插件的配置與使用

    客戶端軟件Subclipse的安裝

    J-hi標準完全版本已經配置好了svn插件,如果沒有的話可以用以下方法安裝:

    Eclipse的使用者可以通過Eclipse的插件自動下載和更新功能來安裝這個插件,在Eclipse的菜單中選擇Help->Software Updates->Find and Install-> Search for new features to install ->New Remote SiteURL中就輸入http://subclipse.tigris.org/updateEclipse就會自已安裝上了。

    安裝完成后,在Eclipseplugins中就會多了5個包,命名為org.tigris.subversion.*的都應該是了。打開Eclipse,window->show view窗口中多了一個SVN文件夾,到此就證明svn插件成功的安裝上了。具體的使用方法,在EclipseHelp中有詳細的幫助Subclipse - Subversion Eclipse Plugin,教你一步一步的使用SVN的客戶端了。如果你對subversion想進行深入的了解,那么看看help中的Version Control with Subversion一定有所收獲。據觀察,這份文檔和sbuversion安裝文件中提供的官方文檔一樣,這里看起來就更舒服些了。

    客戶端配置

    打開svn視圖

    安裝完畢后即可打開svn視圖

    或者顯示視圖:

    更快捷的方式是在右上角,點擊svn視圖圖標:

    C:

    新建資源庫

    輸入url的地址,需要將計算機名轉換成ip地址

    選擇永久接受:

    輸入用戶名和密碼:

    如果一切正常即創建了一個資源庫:

    C:

    可以看到了服務器上的目錄結構。

    SVN服務的使用

    共享項目

    首先需要將現有的項目共享到服務器上:

    選擇svn,下一步:

    選擇建好的資源庫,也可以在這里建資源庫:

    設置文件夾名稱:

    點擊完成,及完成了項目的共享與版本庫連接。

    接下來即可寫入項目第一個版本。

    運行到98%的時候可能會停滯很長時間,耐心等候即可。

    數據提交

    這是可以看到小組菜單里的item已經有變化了。

    修改程序后,即可提交:

    可以看到對程序的改動已經被記錄并提示,是否更新到版本庫。

    點擊確定即可將本地數據提交到服務器版本庫。

    數據下載更新

    在小組中點擊更新即可將服務器版本庫中的版本下載到本地。

    每次開始工作之前從版本庫中下載更新,階段工作完成并測試無誤之后提交。會讓團隊的合作開發變得方便可控。

    參考資源:http://www.uml.org.cn/pzgl/200904106.asp

    刪除或更改項目的資源庫位置

    若要刪除svn服務的資源庫,需要先從項目中刪除svn信息,可在小組中刪除版本共享鏈接先:

    刪除版本共享鏈接

    刪除資源庫位置

    回到svn視圖中,廢棄位置:

    這樣就使開發的源程序斷開了與版本共享庫的鏈接,即退出了svn服務。

    更改資源庫位置只用新建資源庫并配置即可。

    Subclipse的卸載

    卸載的方法也很簡單,也是點擊 Help => Software Updates => Manage Configuration

    http://www.uml.org.cn/pzgl/images/11204a160-12.jpg

    按上圖操作就可以卸載了。


                                     注:該文檔由J-Hi愛好者"尋找本拉登"提供,他的QQ號為382600911,歡迎大家與他在技術上多多交流

    posted @ 2011-04-23 20:13 張昊 閱讀(2131) | 評論 (3)編輯 收藏

    最近在做J-Hi融合SpringJDBC時遇到一個棘手的問題,那就是在insert一條記錄時如何取回記錄主鍵值的?問題主要讓我糾結在對跨數據庫SpringJDBC的處理上,大家都知道象SQLServer或MyServer主鍵的值是以自增的方式,而象Oracle主建的值通過序列生成并通過insert將值直接插入到表中的。為此SpringJDBC提供了兩種機制,
        1、主鍵自增的解決方案
            KeyHolder keyHolder = new GeneratedKeyHolder(); 
            
    this.getJdbcTemplate().update(new PreparedStatementCreator(){

                
    public PreparedStatement createPreparedStatement(Connection con)
                        
    throws SQLException {
       
    PreparedStatement ps
    =con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
     
                    
    return ps;
                }
                
            }, keyHolder);
            
        
    return keyHolder.getKey().intValue();
    keyHolder 數據庫自增主鍵值的持有者,它監聽PreparedStatement的返回的值Statement.RETURN_GENERATED_KEYS獲取主鍵值,并存放在自己的池中(實際上是一個list)一般來說,一個keyHolder實例只綁定一個PreparedStatement的執行,當然最好也只是插入一條數據庫記錄,這樣才能保證池中只有一個主鍵值。
    當keyHolder獲得主鍵值后,您可以在任何時候通過訪問keyHolder對象得到這個主鍵值,也就是說只要它的生命期存在,這個主鍵的值就一直不會丟失。
    總結:1)、在執行
    PreparedStatement之前創建自增主鍵的持有者對象keyHolder
          2)、在創建
    PreparedStatement對象時一定要聲明返回主鍵值,列如con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS)
          3)、只要keyHolder的生命期存在,那么主鍵的值在任何時候與位置你都可以取得到

        2、檢索數據庫序列生成的主鍵的解決方案
            OracleSequenceMaxValueIncrementer incr = new OracleSequenceMaxValueIncrementer(dataSource, "SIMPLE_SEQUENCE");
            
    return incr.nextIntValue();
    象Oracle這樣的數據庫SpringJDBC的解決方案一目了解,通過給定數據源dataSource與序列名"SIMPLE_SEQUENCE"就可以這個序列的最大值。當然還可以通過這個類設計緩沖區大小通過setCacheSize方法,該方法可以一次性取出多個值以減少與數據庫的訪問次數(數據庫的交互是很耗時與耗費資源的)

    J-Hi的問題與解決方法
        因為J-Hi要實現跨數據庫跨多個ORM框架因此對于SpringJDBC這兩種方案必須要融合到一起,并且在總體設計上還要與其它的ORM框架(目前J-Hi已融合的ORM框架有hibernate、ibatis2、ibatis3)的接口聲明相兼容,因此在對SpringJDBC集成的總體設計上我借鑒了hibernate的方言思想,通過方言將SpringJDBC兩種方案融合在J-Hi之中以實現對不同類型數據庫主鍵管理的差異性。
            KeyHolder keyHolder = new GeneratedKeyHolder(); 
            
    this.getJdbcTemplate().update(new PreparedStatementCreator(){

                
    public PreparedStatement createPreparedStatement(Connection con)
                        
    throws SQLException {
      
    ISpringJDBCHiDialect dialect 
    = sessionFactory.getDialect();   
    PreparedStatement ps
    =con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
     
                        
    if(stepFlage == primaryKeyIndex && valueClass.getPropertyName().equals(primaryKeyName)){
                            Number _id 
    = dialect.getSelectKey(entity.getEntityName(), getJdbcTemplate().getDataSource());
                    
    return ps;
                }
                
            }, keyHolder);
            
            
    if(obj.getPrimarykey() == null)
                BeanUtil.setPropertyValue(obj, 
    "id", keyHolder.getKey().intValue());

    從原生的SQL語句上講Oracle在insert時要插入主鍵值,而SQLServer恰好相反必須不能插入主鍵的值,我在設計上就是抓住這一特性,再結合方言,實現了跨數據庫的SpringJDBC, dialect.getSelectKey()方法,對應不同的數據庫方言,如果是oracle就會生成主鍵的值,而如果是SQLServer這個方法不會返回任何值,代碼如下
    Oracle的方言方法:
        public Number getSelectKey(String entityName, DataSource dataSource) {
            OracleSequenceMaxValueIncrementer incr 
    = new OracleSequenceMaxValueIncrementer(dataSource, "HIBERNATE_SEQUENCE");
            
    return incr.nextIntValue();
        }
    SQLServer的方言方法:
        public Number getSelectKey(String entityName, DataSource dataSource) {
    //        自增主鍵不用實現該方法
            return null;
        }
    通過返回主鍵值是否為null,還判斷在拼寫sql時是否插入主鍵字段的值
    最后通過
            if(obj.getPrimarykey() == null)
                BeanUtil.setPropertyValue(obj, 
    "id", keyHolder.getKey().intValue());
    Pojo對象是否主鍵值(如果沒有就說明是自增型的如SQLServer,如果有就說明是序列生成的如Oracle),來將其賦值到POJO的屬性中.
    posted @ 2011-04-21 00:19 張昊 閱讀(1952) | 評論 (3)編輯 收藏

      因為目前很多企業用SpringJDBC框架做數據訪問層,通過調查應大家的要求目前我正在做將SpringJDBC融入J-Hi平臺的工作。
      在以前我還真沒對各數據庫的翻頁處理做深入的分析,只是膚淺的知道SQLServer用top,Oracle用rownum,MySQL用limit通過sql語句做分頁處理,我一直認為通過對應數據庫的這些關鍵字就可以獲取指定的數據條數,而這些數據是在數據庫端就可以一次完成的。例如只取滿足條件的第11-20這10條記錄,這樣ResultSet就會只有10條結果,而事實并非如此,主要就糾結在SQLServer上。
      通過做J-Hi對SpringJDBC融合的開發,我才知道實際上SQLServer2000并不能滿足我們這樣現實的需求,而只有到了SQLServer2005這個局面才有了改觀,下面讓我們對SQLServer的分頁處理做如下分析:

       SQLServer2000,由于它只提供了top關鍵字,而top的作用只是滿足條件的前多少條記錄,因此在處理翻頁時,它是將滿足條件的前多少條記錄一并取出,如每頁10條,翻到第二頁時的sql語句為
    select top 20 HI_Org.* from HI_Org HI_Org
       也就是說會把前20條記錄一次性丟給java形成20條記錄的結果集,而對我們來說因為是第二頁每頁10條,所就是說只要這20條記錄的后10條,前10條是沒有任何意義的垃圾數據,這樣的處理機制不但效率會大大降低,而且隨著頁數的增加,比如我們要翻到第1000頁,那在結果集中就要有10000條記錄,因此也造成了資源的浪費。大家由此會推算出來,越往后翻頁,性能就越低。這種性能的低下不只是無用數據量的增加,而且也造成了對這些無用的數據處理的時間損耗。

       搞笑的時,用了這么久的SQLServer卻昏然不知,等到SQLServer2005微軟才算時對此做了補充與修改,下面是SQLServer2005的SQL語句        

    WITH query AS (select ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMPas __hi_row_nr__, hi_org.* from hi_org hi_org) SELECT * FROM query WHERE __hi_row_nr__ BETWEEN 11 AND 20
       通過上面的語句我們可以看出SQLServer2005提供了ROW_NUMBER()方法[這個方法有點象oracle的rownum,也許微軟對于這個功能就是抄習的甲骨文也不一定,哈哈],以記錄結果集的行數,不過還是點惡心,如果用之個方法還必須進行排序處理,如果沒有order by作修飾這個方法還是無效的。

        通過上面的一個小功能的分析,我真是對微軟及SQLServer產品有些失望,如此的功能要事隔5年才完善它,而且完善的并無新意,更何況象這樣的功能就連mysql這種免費開源的產品都早已實現,而SQLServer還是商業運作,真不知微軟的SQLServer在某些方面上都不如開源的產品它是做何感想?
      


    posted @ 2011-04-17 21:30 張昊 閱讀(2381) | 評論 (3)編輯 收藏

    場景分析

    如果項目大量使用了ajax或者項目使用了類似extjs這種富客戶端框架的朋友們可能會經常碰到一個問題:我們如何為客戶端提供正確有效的數據?例如以下簡單需求:

    有一個界面,用于顯示用戶名、用戶所在公司名稱、用戶擁有的權限名稱,使用ajax去服務端獲取數據。

    我們有以下三個類:

    User:用戶類

    Company:公司類

    Role:角色類

    用戶類1:M角色,用戶類1:1公司。

    這里有一段測試代碼,調用了j-hiJSONObject API進行序列化:

    我們測試結果如下:

    {"user":{"mobile":null,"primarykey":null,"parentEntity":null,"class":class test.User,"dataSymbol":null,"username":"zhangsan","cascadeDirty":false,"roles":[{"rolename":"角色1","primarykey":null,"parentEntity":null,"class":class test.Role,"dataSymbol":null,"cascadeDirty":false,"dirty":false,"deletedFlag":false,"version":1},{"rolename":"角色2","primarykey":null,"parentEntity":null,"class":class test.Role,"dataSymbol":null,"cascadeDirty":false,"dirty":false,"deletedFlag":false,"version":1}],"dirty":false,"deletedFlag":false,"version":null,"company":null},"id":1}

    我們發現,將整個對象序列化了。尤其是company對象,客戶端只需要公司名,但結果是所有屬性都被序列化了。

    我們不需要序列化所有屬性,在新版本的J-Hi中,提供了新的方法,輸出我們需要的屬性,看如下例子:

    輸出結果如下:

    {"user":{"username":"zhangsan","roles":[{"rolename":"角色1"},{"rolename":"角色2"}],"company":{"companyName":"新浪"}},"id":1}

    完美達到我們的要求。

    在某些需求中,我們甚至可以從客戶端發起獲取數據的請求,動態的獲取我們需要的數據,比如我們發起一個請求:

    {

    'entity': 'xxxxx.user.User' ,

    'returnType':'JSON',

    'properties': 'username, company.companyName, roles.rolename'

    },

    請求獲取User類對象的以下屬性username,company.companyName,roles.rolename

    服務器端返回User類型對象,并序列化成JSON返回,返回以下幾個屬性username,company.companName.

    通過j-hi的新JSONObject API,我們可以很方便實現這樣的功能,為客戶端提供任意數據。甚至能實現萬能的服務器查詢API。

    代碼分析:

           JSONObject類一個將多個java對象封裝成一個JSON字符串的工具類,每一個java(POJO)對象都是對象JSON字符串的一個屬性,可以通過addJSONObject(),為要轉換的JSON不斷加入新的java對象。

           缺省在創建JSONObject對象時,構建函數參數已經加了一個java對象,如果JSON可能會有多個java對象拼接而成,就可以通過addJSONObject()累加的方式實現。

        /**

         *添加一個待轉換的java對象,使其作為JSON字符串的一部分

         *@paramjsonPropertyName給定JSON的屬性名

         *@paramobj待轉換的java對象,這個java對象可以是基礎類型比如日期、字符串,也可以是POJO對象,或者是Collection集合類對象

         *@paramobjectProperties返回JSON字符串對應POJO的屬性名列表,屬性名與屬性名之間用逗號分隔,如果該java對象的某個元素是集合也可以支持即集合屬性名.集合元素對象屬性名

         *,例如HiUserPOJO"id,org.orgName,org.id",注意:如果該參數為空

         *則只轉換一級屬性,即它不會級聯的返回屬性的屬性值

         */

        publicvoid addJSONObject(String jsonPropertyName, Object obj, String objectProperties)

        /**

         *獲得封裝后的JSON對象

         *@return返回一個JSON對象的字符串

         */

        public String toString()

    目的與意義:

    1、 在一次客戶端的請求過程中,盡量的壓縮傳輸數據的傳輸量,從而降低帶寬,提高傳輸效率

    2、 提高瀏覽器的對JSON對象的解析速度,對于IE瀏覽器來說9以下的版本對JSON的解析速度都很差,這也是適應目前客戶現場情況解決實際問題的方法

    3、 一個清爽沒有數據冗余的JSON對象,更方便你在客戶端做數據控制,例如根據返回的JSON動態的顯示列表的列數



                                         注:該文檔由J-Hi愛好者"葉青"提供,他的QQ號為405986916,歡迎大家與他在技術上多多交流

    posted @ 2011-04-12 22:44 張昊 閱讀(1854) | 評論 (0)編輯 收藏

       由于對J-Hi新版(j-hi for dwz)的開發工作已進入尾聲,現在已經開始內部測試,預計4月底會對外發布。新版本的截圖如下



       因此我們正在為下一步的工作與下一步的平臺升級做準備工作,在平臺目前的版本中支持Struts2、Webwork、hibernate、ibatis2、ibatis3,我們計劃在下一升級版中融入SpringMVC與SpringJDBC框架,如果興趣參與我們的設計與開發的人員歡迎加入到我們的項目中來。
      
       要求:1、對SpringMVC或SpringJDBC的底層非常熟悉
             2、對J-Hi的底層運行原理有一定了解
             3、要有帶領一個小團隊的組織能力
             4、對中國的開源有興趣與激情,并能始終堅持下來

       工作內容:
             1、編寫相應框架與J-Hi集成的詳細設計文檔
             2、編寫開發計劃的Project
             3、組織開發人員按計劃開發
             4、組織測試工作


       聯系方式:
             郵箱:hao.zhang.hi@gmail.com
             QQ群:133178083
      
       參考:
            http://code.google.com/p/j-hi/


    posted @ 2011-04-09 16:01 張昊 閱讀(1702) | 評論 (2)編輯 收藏

     1 ## displayMenu is defined in WEB-INF/classes/globalMacros.vm
     2 #macro(digui)
     3     #set ($s_parent = $s_owner.parent)
     4     #set( $count = $s_parent.components.size() - 1)
     5     #if($s_parent.components.get($count) == $s_owner)
     6         </ul></li>
     7         #set ($s_owner = $s_owner.parent)
     8         #digui()
     9     #end
    10 #end
    11 
    12 #macro( menuItem $menu $level )
    13   ## set title
    14   #set ($title = $displayer.getMessage($menu.title))
    15   #if ($level == 0)
    16       <li> <a href="javascript:void(0)">${title}</a>
    17           <ul>
    18   #else
    19     <li>
    20     #if ($menu.components.size() > 0)
    21        #set ($numItems = $menu.components.size())
    22          <#if($menu.action)href="$!menu.action"#end #if($menu.jsFunctionName)onclick="$!menu.jsFunctionName" href="javascript:void(0)"#end target="#if($menu.target)$!menu.target#end">${title}</a>
    23       <ul>
    24     #else
    25             <#if($menu.define.checkbox) tname="hi_checkbox_common" tvalue="$!menu.checkbox"#end" #if($menu.action)href="$!menu.action"#end #if($menu.jsFunctionName)onclick="$!menu.jsFunctionName" href="javascript:void(0)"#end target="#if($menu.target)$!menu.target#end">${title}</a>
    26     #end
    27     #if($menu.components.size() == 0)
    28       </li>
    29       #end
    30       #if ($level != 0 && $velocityCount == $menu.parent.components.size() && $menu.components.size() == 0)
    31            #set ($s_owner = $menu)
    32         #digui()
    33     #end
    34   #end
    35 #end
    36 
    37  <script type="text/javascript">
    38 ${menu.define.javascript}
    39 #if($menu.define.checkbox)
    40     function selectedcb(button){
    41     var checkeds = jQuery(button).parent().find(".tree :checkbox").filter(":checked").filter("[name]");
    42     var ids = new Array();
    43     var texts = new Array();
    44     checkeds.each(function(i){
    45         var input = jQuery(this);
    46         ids[i] = input.val();
    47         texts[i] = input.attr("text");
    48     });
    49     var result = new Array();
    50     if(ids.length == 0)
    51         return result;
    52     result[0= ids;result[1= texts;
    53     return result;
    54 }
    55 #end
    56  </script>
    57 
    58 <div style=" float:left; display:block; margin:10px; overflow:auto; width:200px; height:300px; border:solid 1px #CCC; line-height:21px; background:#FFF;"> 
    59     <ul class="tree treeFolder collapse#if($menu.define.checkbox) treeCheck#end">
    60 #displayMenu($menu 0)
    61 </ul>
    62 #if($menu.define.checkbox)
    63 <input type='button' name='button1' value='帶回'  onclick='bringBackCheckBox(selectedcb(this))'/ >
    64 #end
    65 </div>
    66 
    67 
    68 
    posted @ 2011-04-09 00:21 張昊 閱讀(2714) | 評論 (0)編輯 收藏

    僅列出標題
    共5頁: 上一頁 1 2 3 4 5 下一頁 
    主站蜘蛛池模板: 丝瓜app免费下载网址进入ios| 亚洲综合免费视频| 午夜亚洲国产理论秋霞| 亚洲w码欧洲s码免费| 日韩亚洲人成在线综合| 午夜影视日本亚洲欧洲精品一区| 中文字幕无码免费久久99| 一区二区三区免费看| 亚洲成人动漫在线观看| 亚洲一区二区三区在线播放| **aaaaa毛片免费| 成人免费夜片在线观看| 91亚洲国产成人久久精品| 男人的天堂亚洲一区二区三区 | 3d成人免费动漫在线观看| 亚洲欧洲精品成人久久曰| 亚洲成色WWW久久网站| 成人永久福利免费观看| 久久精品人成免费| 一区二区在线免费视频| 亚洲乱理伦片在线观看中字| 日韩亚洲一区二区三区| 四虎永久精品免费观看| 亚洲免费网站在线观看| 拍拍拍无挡视频免费观看1000| 亚洲欧美日韩中文高清www777| 亚洲午夜久久久精品影院| 成人亚洲网站www在线观看| 福利免费观看午夜体检区| a级毛片高清免费视频| 亚洲AV永久无码精品一福利| 亚洲高清在线mv| 亚洲国产精品无码一线岛国| 国产一级大片免费看| 成人性生免费视频| 久热中文字幕在线精品免费| 日本视频免费高清一本18| 一级做a爰全过程免费视频毛片| 亚洲人片在线观看天堂无码| 亚洲国产综合自在线另类| 亚洲乱亚洲乱淫久久|