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

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

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

    (轉(zhuǎn)貼) jqGrid整理

    原帖地址:
    http://www.cnblogs.com/mycoding/archive/2011/07/07/2099878.html

    一、 jqGrid的加載。

    1.引用相關(guān)頭文件

    引入CSS:

    <link href="Scripts/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css" />

    <link href="Scripts/ui.jqgrid.css" rel="stylesheet" type="text/css" />

    引入JS:

    <script src="Scripts/jquery-1.5.1.js" type="text/javascript"></script>

    <script src="Scripts/jquery-ui.min.js" type="text/javascript"></script>

    <script src="Scripts/grid.locale-en.js" type="text/javascript"></script>

    <script src="Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>

    因?yàn)閖qGrid3.6及以后的版本集成了jQuery UI,所以,此處需要導(dǎo)入U(xiǎn)I相關(guān)js和css。另外grid.locale-en.js這個(gè)語(yǔ)言文件必須在jquery.jqGrid.min.js之前加載,否則會(huì)出問(wèn)題。

    2.將jqgrid加入頁(yè)面中

    根據(jù)jqGrid的文檔,要想生成一個(gè)jqGrid,最直接的方法就是:

    $("#list").jqGrid(options);

    其中l(wèi)ist是頁(yè)面上的一個(gè)table:<table id="list"></table>

    下面是一個(gè)簡(jiǎn)單的例子:

    <script type="text/javascript">
     
    $(document).ready(function () {
     
    jQuery("#list").jqGrid({
     
    url: 'Handler.ashx',
     
    datatype: "json",
     
    mtype: 'GET',
     
    colNames: ['SalesReasonID', 'Name', 'ReasonType', 'ModifiedDate'],
     
    colModel: [
     
    { name: 'SalesReasonID', index: 'SalesReasonID', width: 40, align: "left", editable: true },
     
    { name: 'Name', index: 'Name', width: 100, align: "center" },
     
    { name: 'ReasonType', index: 'ReasonType', width: 100, align: "center" },
     
    { name: 'ModifiedDate', index: 'ModifiedDate', width: 150, align: "center", search: false }
     
    ],
     
    rowList: [10, 20, 30],
     
    sortname: 'SalesReasonID',
     
    viewrecords: true,
     
    sortorder: "desc",
     
    jsonReader: {
     
    root: "griddata",
     
    total: "totalpages",
     
    page: "currpage",
     
    records: "totalrecords",
     
    repeatitems: false
     
    },
     
    pager: jQuery('#pager'),
     
    rowNum: 5,
     
    altclass: 'altRowsColour',
     
    //width: 'auto',
     
    width: '500',
     
    height: 'auto',
     
    caption: "DemoGrid"
     
    }).navGrid('#pager', { add: true, edit: true, del: true,search:false,refresh:false }); ;
     
    })

    二、 jqgrid的重要選項(xiàng)

    具體的options參考,可以訪問(wèn)jqGrid文檔關(guān)于option的章節(jié)(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options)。其中有幾個(gè)是比較常用的,重點(diǎn)介紹一下:

    • url :jqGrid控件通過(guò)這個(gè)參數(shù)得到需要顯示的數(shù)據(jù),具體的返回值可以使XML也可以是Json。
    • datatype :這個(gè)參數(shù)用于設(shè)定將要得到的數(shù)據(jù)類(lèi)型。類(lèi)型包括:json 、xml、xmlstring、local、javascript、function。
    • mtype : 定義使用哪種方法發(fā)起請(qǐng)求,GET或者POST。
    • height :Grid的高度,可以接受數(shù)字、%值、auto,默認(rèn)值為150。
    • width :Grid的寬度,如果未設(shè)置,則寬度應(yīng)為所有列寬的之和;如果設(shè)置了寬度,則每列的寬度將會(huì)根據(jù)shrinkToFit選項(xiàng)的設(shè)置,進(jìn)行設(shè)置。
    • shrinkToFit :此選項(xiàng)用于根據(jù)width計(jì)算每列寬度的算法。默認(rèn)值為true。如果shrinkToFit為true且設(shè)置了width值,則每列寬度會(huì)根據(jù) width成比例縮放;如果shrinkToFit為false且設(shè)置了width值,則每列的寬度不會(huì)成比例縮放,而是保持原有設(shè)置,而Grid將會(huì)有 水平滾動(dòng)條。
    • autowidth :默認(rèn)值為false。如果設(shè)為true,則Grid的寬度會(huì)根據(jù)父容器的寬度自動(dòng)重算。重算僅發(fā)生在Grid初始化的階段;如果當(dāng)父容器尺寸變化了,同時(shí)也需要變化Grid的尺寸的話,則需要在自己的代碼中調(diào)用setGridWidth方法來(lái)完成。
    • pager :定義頁(yè)碼控制條Page Bar,在上面的例子中是用一個(gè)div(<div id=”pager”></div>)來(lái)放置的。
    • sortname :指定默認(rèn)的排序列,可以是列名也可以是數(shù)字。此參數(shù)會(huì)在被傳遞到Server端。
    • viewrecords :設(shè)置是否在Pager Bar顯示所有記錄的總數(shù)。
    • caption :設(shè)置Grid表格的標(biāo)題,如果未設(shè)置,則標(biāo)題區(qū)域不顯示。
    • rowNum :用于設(shè)置Grid中一次顯示的行數(shù),默認(rèn)值為20。正是這個(gè)選項(xiàng)將參數(shù)rows(prmNames中設(shè)置的)通過(guò)url選項(xiàng)設(shè)置的鏈接傳遞到Server。注意如果Server返回的數(shù)據(jù)行數(shù)超過(guò)了rowNum的設(shè)定,則Grid也只顯示rowNum設(shè)定的行數(shù)。
    • rowList :一個(gè)數(shù)組,用于設(shè)置Grid可以接受的rowNum值。例如[10,20,30]。
    • colNames :字符串?dāng)?shù)組,用于指定各列的題頭文本,與列的順序是對(duì)應(yīng)的。
    • colModel :最重要的數(shù)組之一,用于設(shè)定各列的參數(shù)。(稍后詳述)
    • prmNames :這是一個(gè)數(shù)組,用于設(shè)置jqGrid將要向Server傳遞的參數(shù)名稱(chēng)。(稍后詳述)
    • jsonReader :這又是一個(gè)數(shù)組,用來(lái)設(shè)定如何解析從Server端發(fā)回來(lái)的json數(shù)據(jù)。(稍后詳述)

    2.1 prmNames選項(xiàng)

    prmNames是jqGrid的一個(gè)重要選項(xiàng),用于設(shè)置jqGrid將要向Server傳遞的參數(shù)名稱(chēng)。其默認(rèn)值為:

    prmNames : {

    page:"page", // 表示請(qǐng)求頁(yè)碼的參數(shù)名稱(chēng)

    rows:"rows", // 表示請(qǐng)求行數(shù)的參數(shù)名稱(chēng)

    sort: "sidx", // 表示用于排序的列名的參數(shù)名稱(chēng)

    order: "sord", // 表示采用的排序方式的參數(shù)名稱(chēng)

    search:"_search", // 表示是否是搜索請(qǐng)求的參數(shù)名稱(chēng)

    nd:"nd", // 表示已經(jīng)發(fā)送請(qǐng)求的次數(shù)的參數(shù)名稱(chēng)

    id:"id", // 表示當(dāng)在編輯數(shù)據(jù)模塊中發(fā)送數(shù)據(jù)時(shí),使用的id的名稱(chēng)

    oper:"oper", // operation參數(shù)名稱(chēng)

    editoper:"edit", // 當(dāng)在edit模式中提交數(shù)據(jù)時(shí),操作的名稱(chēng)

    addoper:"add", // 當(dāng)在add模式中提交數(shù)據(jù)時(shí),操作的名稱(chēng)

    deloper:"del", // 當(dāng)在delete模式中提交數(shù)據(jù)時(shí),操作的名稱(chēng)

    subgridid:"id", // 當(dāng)點(diǎn)擊以載入數(shù)據(jù)到子表時(shí),傳遞的數(shù)據(jù)名稱(chēng)

    npage: null,

    totalrows:"totalrows" // 表示需從Server得到總共多少行數(shù)據(jù)的參數(shù)名稱(chēng),參見(jiàn)jqGrid選項(xiàng)中的rowTotal

    }

    2.2 jsonReader選項(xiàng)

    jsonReader是jqGrid的一個(gè)重要選項(xiàng),用于設(shè)置如何解析從Server端發(fā)回來(lái)的json數(shù)據(jù),如果Server返回的是xml數(shù)據(jù),則對(duì)應(yīng)的使用xmlReader來(lái)解析。jsonReader的默認(rèn)值為:

    jsonReader : {

    root: "rows", // json中代表實(shí)際模型數(shù)據(jù)的入口

    page: "page", // json中代表當(dāng)前頁(yè)碼的數(shù)據(jù)

    total: "total", // json中代表頁(yè)碼總數(shù)的數(shù)據(jù)

    records: "records", // json中代表數(shù)據(jù)行總數(shù)的數(shù)據(jù)

    repeatitems: true, // 如果設(shè)為false,則jqGrid在解析json時(shí),會(huì)根據(jù)name來(lái)搜索對(duì)應(yīng)的數(shù)據(jù)元素(即可以json中元素可以不按順序);而所使用的name是來(lái)自于colModel中的name設(shè)定。

    cell: "cell",

    id: "id",

    userdata: "userdata",

    subgrid: {

    root:"rows",

    repeatitems: true,

    cell:"cell"

    }

    }

    假如有下面一個(gè)json字符串:

    {"totalpages":"3","currpage":"1","totalrecords":"11","griddata": [{"SalesReasonID":"1","Name":"Price","ReasonType":"Other","ModifiedDate":"1998 年6月1日"},{"SalesReasonID":"2","Name":"On Promotion","ReasonType":"Promotion","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"3","Name":"Magazine Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"4","Name":"Television Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"5","Name":"Manufacturer","ReasonType":"Other","ModifiedDate":"1998 年6月1日"}]}

    其對(duì)應(yīng)的jsonReader為:jsonReader: {

    root: "griddata",

    total: "totalpages",

    page: "currpage",

    records: "totalrecords",

    repeatitems: false

    }

    注:cell、id在repeatitems為true時(shí)可以用到,即每一個(gè)記錄是由一對(duì)id和cell組合而成,即可以適用另一種json結(jié)構(gòu)。援引文檔中的例子:

    repeatitems為true時(shí):

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords"

         },  

         ...  

    });  

    json結(jié)構(gòu)為:

    {   

    "totalpages": "xxx",   

    "currpage": "yyy",  

    "totalrecords": "zzz",  

    "invdata" : [  

                      {"id" :"1", "cell" :["cell11", "cell12", "cell13"]},   // cell中不需要各列的name,只要值就OK了,但是需要保持對(duì)應(yīng)

                      {"id" :"2", "cell" :["cell21", "cell22", "cell23"]},  

                      ...  

         ]  

    }  

    repeatitems為false時(shí):

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords",  

             repeatitems: false,  

             id: "0"

         },  

         ...  

    });  

    json結(jié)構(gòu)為:

    {   

    "totalpages" : "xxx",   

    "currpage" : "yyy",  

    "totalrecords" : "zzz",  

    "invdata" : [  

                     {"invid" : "1","invdate":"cell11", "amount" :"cell12", "tax" :"cell13", "total" :"1234", "note" :"somenote"}, // 數(shù)據(jù)中需要各列的name,但是可以不按列的順序

                      {"invid" : "2","invdate":"cell21", "amount" :"cell22", "tax" :"cell23", "total" :"2345", "note" :"some note"},  

                      ...  

         ]  

    }  

    2.3 colModel的重要選項(xiàng)

    colModel也有許多非常重要的選項(xiàng),在使用搜索、排序等方面都會(huì)用到。這里先只說(shuō)說(shuō)最基本的。

    • name :為Grid中的每個(gè)列設(shè)置唯一的名稱(chēng),這是一個(gè)必需選項(xiàng),其中保留字包括subgrid、cb、rn。
    • index :設(shè)置排序時(shí)所使用的索引名稱(chēng),這個(gè)index名稱(chēng)會(huì)作為sidx參數(shù)(prmNames中設(shè)置的)傳遞到Server。
    • label :當(dāng)jqGrid的colNames選項(xiàng)數(shù)組為空時(shí),為各列指定題頭。如果colNames和此項(xiàng)都為空時(shí),則name選項(xiàng)值會(huì)成為題頭。
    • width :設(shè)置列的寬度,目前只能接受以px為單位的數(shù)值,默認(rèn)為150。
    • sortable :設(shè)置該列是否可以排序,默認(rèn)為true。
    • search :設(shè)置該列是否可以被列為搜索條件,默認(rèn)為true。
    • resizable :設(shè)置列是否可以變更尺寸,默認(rèn)為true。
    • hidden :設(shè)置此列初始化時(shí)是否為隱藏狀態(tài),默認(rèn)為false。
    • formatter :預(yù)設(shè)類(lèi)型或用來(lái)格式化該列的自定義函數(shù)名。常用預(yù)設(shè)格式有:integer、date、currency、number等(具體參見(jiàn)文檔 )。

    三、 注意事項(xiàng)

    1. 動(dòng)態(tài)改變Add Form或者Edit Form中的select的內(nèi)容,如:改變下圖中的Comparator下拉中的內(nèi)容。

    clip_image002

    $("#list_d").navGrid('#pager_d',{add:true,edit:true,del:true,search:false,refresh:false},

    {

    checkOnSubmit:false, closeAfterEdit: true,recreateForm:true,

    beforeInitData:function(formid){

    initComparator();

    },

    beforeShowForm: function(formid){

    $("#list_d").jqGrid('setColProp', 'Name', { editrules:{required:false},});

    $('#tr_Name', formid).hide();

    }

    },//edit

    {},//add

    {}//del

    beforeInitData, beforeShowForm在每次點(diǎn)擊編輯的時(shí)候都會(huì)執(zhí)行。initComparator的作用是通過(guò)ajax獲取數(shù)據(jù),然后利 用$("#list_d").jqGrid('setColProp', 'Comparator', { editoptions: { value: valueString} });來(lái)設(shè)置Comparator下拉中的內(nèi)容。其中valueString的格式如下’ equal to: equal to; not equal to: not equal to’。鍵值之間用冒號(hào)隔開(kāi),2項(xiàng)之間用分號(hào)隔開(kāi)。注意:把recreateForm設(shè)為true,否則'setColProp'只在第一次調(diào)用時(shí)有效。

    2. var rowNum = parseInt($(this).getGridParam("records"), 10); 得到數(shù)據(jù)條數(shù)。

    3. jQuery("#list_d").clearGridData();清空數(shù)據(jù)。

    4. jQuery("#list").getCell(ids,"Key");獲取第ids行的key列。

    5. $("#list").jqGrid('setSelection', "1");選中第一行。放在loadComplete:中在gird加載完成的時(shí)候自動(dòng)選中第一行。 loadComplete:function(data){$("#list").jqGrid('setSelection', "1");

    }

    6. 對(duì)于像1中的可編輯的字段,可以設(shè)定rule,參見(jiàn)http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules#editrules

    7. 修改Option,以URL為例

    jQuery("#list_d").jqGrid('setGridParam',{url:"xxx.aspx",page:1}).trigger('reloadGrid');


    復(fù)雜的表格可以參考jquery grid demo網(wǎng)站 :




    posted @ 2011-11-01 14:23 AK47 閱讀(2320) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)載)Spring 注解@Component,@Service,@Controller,@Repository

    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個(gè)擁有特殊語(yǔ)義的注釋?zhuān)鼈兎謩e是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個(gè)注釋和 @Component 是等效的,但是從注釋類(lèi)的命名上,很容易看出這 3 個(gè)注釋分別和持久層、業(yè)務(wù)層和控制層(Web 層)相對(duì)應(yīng)。雖然目前這 3 個(gè)注釋和 @Component 相比沒(méi)有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository、@Service 和 @Controller 對(duì)分層中的類(lèi)進(jìn)行注釋?zhuān)?@Component 對(duì)那些比較中立的類(lèi)進(jìn)行注釋。

    在 一個(gè)稍大的項(xiàng)目中,通常會(huì)有上百個(gè)組件,如果這些組件采用xml的bean定義來(lái)配置,顯然會(huì)增加配置文件的體積,查找以及維護(hù)起來(lái)也不太方便。 Spring2.5為我們引入了組件自動(dòng)掃描機(jī)制,他可以在類(lèi)路徑底下尋找標(biāo)注了 @Component,@Service,@Controller,@Repository注解的類(lèi),并把這些類(lèi)納入進(jìn)spring容器中管理。它的作用 和在xml文件中使用bean節(jié)點(diǎn)配置組件時(shí)一樣的。要使用自動(dòng)掃描機(jī)制,我們需要打開(kāi)以下配置信息: 
    Java代碼

    1. <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-2.5.xsd"  
    2. >  
    3.   
    4. <context:component-scan base-package=”com.eric.spring”>   
    5. </beans>   
       /*其中base-package為需要掃描的包(含所有子包)

         @Service用于標(biāo)注業(yè)務(wù)層組件,

         @Controller用于標(biāo)注控制層組件(如struts中的action),

         @Repository用于標(biāo)注數(shù)據(jù)訪問(wèn)組件,即DAO組件,

         @Component泛指組件,當(dāng)組件不好歸類(lèi)的時(shí)候,我們可以使用這個(gè)注解進(jìn)行標(biāo)注。

        */   


    6. @Service public class VentorServiceImpl implements iVentorService {   
    7. } @Repository public class VentorDaoImpl implements iVentorDao {  
    8. }

    /*getBean的默認(rèn)名稱(chēng)是類(lèi)名(頭字母小 寫(xiě)),如果想自定義,可以@Service(“aaaaa”)這樣來(lái)指定,這種bean默認(rèn)是單例的,如果想改變,可以使用 @Service(“beanName”) @Scope(“prototype”)來(lái)改變。可以使用以下方式指定初始化方法和銷(xiāo)毀方法(方法名任意): @PostConstruct public void init() {  

    */
    9. }  
    10. @PreDestroy public void destory() {  
    11. } 

    注入方式:

    把 DAO實(shí)現(xiàn)類(lèi)注入到service實(shí)現(xiàn)類(lèi)中,把service的接口(注意不要是service的實(shí)現(xiàn)類(lèi))注入到action中,注入時(shí)不要new 這個(gè)注入的類(lèi),因?yàn)閟pring會(huì)自動(dòng)注入,如果手動(dòng)再new的話會(huì)出現(xiàn)錯(cuò)誤,然后屬性加上@Autowired后不需要getter()和 setter()方法,Spring也會(huì)自動(dòng)注入。至于更具體的內(nèi)容,等對(duì)注入的方式更加熟練后會(huì)做個(gè)完整的例子上來(lái)。

    注解:

    在 spring的配置文件里面只需要加上<context:annotation-config/> 和<context:component-scan base-package="需要實(shí)現(xiàn)注入的類(lèi)所在包"/>,可以使用base-package="*"表示全部的類(lèi)。   

    <context:component-scan base-package=”com.eric.spring”> 

    其中base-package為需要掃描的包(含所有子包)

    在接口前面標(biāo)上@Autowired和@Qualifier注釋使得接口可以被容器注入,當(dāng)接口存在兩個(gè)實(shí)現(xiàn)類(lèi)的時(shí)候必須指定其中一個(gè)來(lái)注入,使用實(shí)現(xiàn)類(lèi)首字母小寫(xiě)的字符串來(lái)注入,如:

    1.     @Autowired     
    2.   
    3.     @Qualifier("chinese")      
    4.   
    5.     private Man man;   

    否則可以省略,只寫(xiě)@Autowired   。 

    @Service服務(wù)層組件,用于標(biāo)注業(yè)務(wù)層組件,表示定義一個(gè)bean,自動(dòng)根據(jù)bean的類(lèi)名實(shí)例化一個(gè)首寫(xiě)字母為小寫(xiě)的bean,例如Chinese實(shí)例化為chinese,如果需要自己改名字則:@Service("你自己改的bean名")。   

    @Controller用于標(biāo)注控制層組件(如struts中的action)

    @Repository持久層組件,用于標(biāo)注數(shù)據(jù)訪問(wèn)組件,即DAO組件

    @Component泛指組件,當(dāng)組件不好歸類(lèi)的時(shí)候,我們可以使用這個(gè)注解進(jìn)行標(biāo)注。 


    @Service 
    public class VentorServiceImpl implements iVentorService { 
    }

    @Repository 
    public class VentorDaoImpl implements iVentorDao { 


    getBean 的默認(rèn)名稱(chēng)是類(lèi)名(頭字母小寫(xiě)),如果想自定義,可以@Service(“aaaaa”) 這樣來(lái)指定,這種

    bean默認(rèn)是單例的,如果想改變,可以使用@Service(“beanName”) @Scope(“prototype”)來(lái)改變。

    可以使用以下方式指定初始化方法和銷(xiāo)毀方法(方法名任意):

    @PostConstruct

    public void init() { 



    @PreDestroy

    public void destory() { 

    }

    posted @ 2011-10-10 16:46 AK47 閱讀(49714) | 評(píng)論 (3)編輯 收藏

    (轉(zhuǎn)貼)使用 Spring 2.5 注釋驅(qū)動(dòng)的 IoC 功能

    原帖地址
    http://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/

    概述

    注釋配置相對(duì)于 XML 配置具有很多的優(yōu)勢(shì):

    • 它可以充分利用 Java 的反射機(jī)制獲取類(lèi)結(jié)構(gòu)信息,這些信息可以有效減少配置的工作。如使用 JPA 注釋配置 ORM 映射時(shí),我們就不需要指定 PO 的屬性名、類(lèi)型等信息,如果關(guān)系表字段和 PO 屬性名、類(lèi)型都一致,您甚至無(wú)需編寫(xiě)任務(wù)屬性映射信息——因?yàn)檫@些信息都可以通過(guò) Java 反射機(jī)制獲取。
    • 注釋和 Java 代碼位于一個(gè)文件中,而 XML 配置采用獨(dú)立的配置文件,大多數(shù)配置信息在程序開(kāi)發(fā)完成后都不會(huì)調(diào)整,如果配置信息和 Java 代碼放在一起,有助于增強(qiáng)程序的內(nèi)聚性。而采用獨(dú)立的 XML 配置文件,程序員在編寫(xiě)一個(gè)功能時(shí),往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會(huì)降低開(kāi)發(fā)效率。

    因此在很多情況下,注釋配置比 XML 配置更受歡迎,注釋配置有進(jìn)一步流行的趨勢(shì)。Spring 2.5 的一大增強(qiáng)就是引入了很多注釋類(lèi),現(xiàn)在您已經(jīng)可以使用注釋配置完成大部分 XML 配置的功能。在這篇文章里,我們將向您講述使用注釋進(jìn)行 Bean 定義和依賴(lài)注入的內(nèi)容。

     
    原來(lái)我們是怎么做的      
    在使用注釋配置之前,先來(lái)回顧一下傳統(tǒng)上是如何配置 Bean 并完成 Bean 之間依賴(lài)關(guān)系的建立。下面是 3 個(gè)類(lèi),它們分別是 Office、Car 和 Boss,這 3 個(gè)類(lèi)需要在 Spring 容器中配置為 Bean:    
       
    Office 僅有一個(gè)屬性:    
         
    清單 1. Office.java    
                        
    package com.baobaotao;    
    public class Office {    
        private String officeNo =”001”;    
       
        //省略 get/setter    
       
        @Override   
        public String toString() {    
            return "officeNo:" + officeNo;    
        }    
    }    
           
    Car 擁有兩個(gè)屬性:    
         
    清單 2. Car.java 
                         
    package com.baobaotao;    
       
    public class Car {    
        private String brand;    
        private double price;    
       
        // 省略 get/setter    
       
        @Override   
        public String toString() {    
            return "brand:" + brand + "," + "price:" + price;    
        }    
    }    
          
    Boss 擁有 Office 和 Car 類(lèi)型的兩個(gè)屬性:    
      
    清單 3. Boss.java    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
       
        // 省略 get/setter    
       
        @Override   
        public String toString() {    
            return "car:" + car + "\n" + "office:" + office;    
        }    
    }    
        
    我們?cè)?Spring 容器中將 Office 和 Car 聲明為 Bean,并注入到 Boss Bean 中:下面是使用傳統(tǒng) XML 完成這個(gè)工作的配置文件 beans.xml:    
        
    清單 4. beans.xml 將以上三個(gè)類(lèi)配置成 Bean    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">    
        <bean id="boss" class="com.baobaotao.Boss">    
            <property name="car" ref="car"/>    
            <property name="office" ref="office" />    
        </bean>    
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="002"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
    當(dāng)我們運(yùn)行以下代碼時(shí),控制臺(tái)將正確打出 boss 的信息:    
      
    清單 5. 測(cè)試類(lèi):AnnoIoCTest.java    
                        
    import org.springframework.context.ApplicationContext;    
    import org.springframework.context.support.ClassPathXmlApplicationContext;    
    public class AnnoIoCTest {    
       
        public static void main(String[] args) {    
            String[] locations = {"beans.xml"};    
            ApplicationContext ctx =     
                new ClassPathXmlApplicationContext(locations);    
            Boss boss = (Boss) ctx.getBean("boss");    
            System.out.println(boss);    
        }    
    }    
        
    這說(shuō)明 Spring 容器已經(jīng)正確完成了 Bean 創(chuàng)建和裝配的工作。    
         
    使用 @Autowired 注釋    
       
    Spring 2.5 引入了 @Autowired 注釋?zhuān)梢詫?duì)類(lèi)成員變量、方法及構(gòu)造函數(shù)進(jìn)行標(biāo)注,完成自動(dòng)裝配的工作。來(lái)看一下使用 @Autowired 進(jìn)行成員變量自動(dòng)注入的代碼:    
      
    清單 6. 使用 @Autowired 注釋的 Boss.java    
                        
    package com.baobaotao;    
    import org.springframework.beans.factory.annotation.Autowired;    
       
    public class Boss {    
       
        @Autowired   
        private Car car;    
       
        @Autowired   
        private Office office;    
       
        …    
    }    
           
    Spring 通過(guò)一個(gè) BeanPostProcessor 對(duì) @Autowired 進(jìn)行解析,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。   

    清單 7. 讓 @Autowired 注釋工作起來(lái)    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">    
       
        <!-- 該 BeanPostProcessor 將自動(dòng)起作用,對(duì)標(biāo)注 @Autowired 的 Bean 進(jìn)行自動(dòng)注入 -->    
        <bean class="AutowiredAnnotationBeanPostProcessor  
            org.springframework.beans.factory.annotation.  "/>    
       
        <!-- 移除 boss Bean 的屬性注入配置的信息 -->    
        <bean id="boss" class="com.baobaotao.Boss"/>    
         
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="001"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
        
    這 樣,當(dāng) Spring 容器啟動(dòng)時(shí),AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當(dāng)發(fā)現(xiàn) Bean 中擁有 @Autowired 注釋時(shí)就找到和其匹配(默認(rèn)按類(lèi)型匹配)的 Bean,并注入到對(duì)應(yīng)的地方中去。    
       
    按 照上面的配置,Spring 將直接采用 Java 反射機(jī)制對(duì) Boss 中的 car 和 office 這兩個(gè)私有成員變量進(jìn)行自動(dòng)注入。所以對(duì)成員變量使用 @Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。    
       
    當(dāng)然,您也可以通過(guò) @Autowired 對(duì)方法或構(gòu)造函數(shù)進(jìn)行標(biāo)注,來(lái)看下面的代碼:    
        
    清單 8. 將 @Autowired 注釋標(biāo)注在 Setter 方法上    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
       
         @Autowired   
        public void setCar(Car car) {    
            this.car = car;    
        }    
         
        @Autowired   
        public void setOffice(Office office) {    
            this.office = office;    
        }    
        …    
    }    
         
    這時(shí),@Autowired 將查找被標(biāo)注的方法的入?yún)㈩?lèi)型的 Bean,并調(diào)用方法自動(dòng)注入這些 Bean。而下面的使用方法則對(duì)構(gòu)造函數(shù)進(jìn)行標(biāo)注:    
        
    清單 9. 將 @Autowired 注釋標(biāo)注在構(gòu)造函數(shù)上    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
         
        @Autowired   
        public Boss(Car car ,Office office){    
            this.car = car;    
            this.office = office ;    
        }    
         
        …    
    }    
           
    由于 Boss() 構(gòu)造函數(shù)有兩個(gè)入?yún)ⅲ謩e是 car 和 office,@Autowired 將分別尋找和它們類(lèi)型匹配的 Bean,將它們作為 Boss(Car car ,Office office) 的入?yún)?lái)創(chuàng)建 Boss Bean。    
         
    當(dāng)候選 Bean 數(shù)目不為 1 時(shí)的應(yīng)對(duì)方法    
       
    在 默認(rèn)情況下使用 @Autowired 注釋進(jìn)行自動(dòng)注入時(shí),Spring 容器中匹配的候選 Bean 數(shù)目必須有且僅有一個(gè)。當(dāng)找不到一個(gè)匹配的 Bean 時(shí),Spring 容器將拋出 BeanCreationException 異常,并指出必須至少擁有一個(gè)匹配的 Bean。我們可以來(lái)做一個(gè)實(shí)驗(yàn):    
       
       
    清單 10. 候選 Bean 數(shù)目為 0 時(shí)    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
         xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ">    
         
        <bean class="AutowiredAnnotationBeanPostProcessor  
            org.springframework.beans.factory.annotation.  "/>     
       
        <bean id="boss" class="com.baobaotao.Boss"/>    
       
        <!-- 將 office Bean 注釋掉 -->    
        <!-- <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
        </bean>-->    
       
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
    由于 office Bean 被注釋掉了,所以 Spring 容器中將沒(méi)有類(lèi)型為 Office 的 Bean 了,而 Boss 的 office 屬性標(biāo)注了 @Autowired,當(dāng)啟動(dòng) Spring 容器時(shí),異常就產(chǎn)生了。    
       
    當(dāng) 不能確定 Spring 容器中一定擁有某個(gè)類(lèi)的 Bean 時(shí),可以在需要自動(dòng)注入該類(lèi) Bean 的地方可以使用 @Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時(shí)也不報(bào)錯(cuò)。來(lái)看一下具體的例子:    
       
       
    清單 11. 使用 @Autowired(required = false)    
                        
    package com.baobaotao;    
       
    import org.springframework.beans.factory.annotation.Autowired;    
    import org.springframework.beans.factory.annotation.Required;    
       
    public class Boss {    
       
        private Car car;    
        private Office office;    
       
        @Autowired   
        public void setCar(Car car) {    
            this.car = car;    
        }    
        @Autowired(required = false)    
        public void setOffice(Office office) {    
            this.office = office;    
        }    
        …    
    }    
        
    當(dāng) 然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動(dòng)注入而又允許不注入的情況一般僅會(huì)在開(kāi)發(fā)期或測(cè)試期碰到(如為了快速啟動(dòng) Spring 容器,僅引入一些模塊的 Spring 配置文件),所以 @Autowired(required = false) 會(huì)很少用到。    
       
    和找不到一個(gè)類(lèi)型匹配 Bean 相反的一個(gè)錯(cuò)誤是:如果 Spring 容器中擁有多個(gè)候選 Bean,Spring 容器在啟動(dòng)時(shí)也會(huì)拋出 BeanCreationException 異常。來(lái)看下面的例子:    
        
    清單 12. 在 beans.xml 中配置兩個(gè) Office 類(lèi)型的 Bean    
                        
    …     
    <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
    </bean>    
    <bean id="office2" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
    </bean>    
    …    
         
    我們?cè)?Spring 容器中配置了兩個(gè)類(lèi)型為 Office 類(lèi)型的 Bean,當(dāng)對(duì) Boss 的 office 成員變量進(jìn)行自動(dòng)注入時(shí),Spring 容器將無(wú)法確定到底要用哪一個(gè) Bean,因此異常發(fā)生了。    
       
    Spring 允許我們通過(guò) @Qualifier 注釋指定注入 Bean 的名稱(chēng),這樣歧義就消除了,可以通過(guò)下面的方法解決異常:    
      
    清單 13. 使用 @Qualifier 注釋指定注入 Bean 的名稱(chēng)    
                        
    @Autowired   
    public void setOffice(@Qualifier("office")Office office) {    
        this.office = office;    
    }    
        
     
    @Qualifier("office") 中的 office 是 Bean 的名稱(chēng),所以 @Autowired 和 @Qualifier 結(jié)合使用時(shí),自動(dòng)注入的策略就從 byType 轉(zhuǎn)變成 byName 了。@Autowired 可以對(duì)成員變量、方法以及構(gòu)造函數(shù)進(jìn)行注釋?zhuān)?@Qualifier 的標(biāo)注對(duì)象是成員變量、方法入?yún)ⅰ?gòu)造函數(shù)入?yún)ⅰU怯捎谧⑨寣?duì)象的不同,所以 Spring 不將 @Autowired 和 @Qualifier 統(tǒng)一成一個(gè)注釋類(lèi)。下面是對(duì)成員變量和構(gòu)造函數(shù)入?yún)⑦M(jìn)行注釋的代碼:    
       
    對(duì)成員變量進(jìn)行注釋?zhuān)?nbsp;   
      
    清單 14. 對(duì)成員變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        @Autowired   
        private Car car;    
         
        @Autowired   
        @Qualifier("office")    
        private Office office;    
        …    
    }    
         
        
    對(duì)構(gòu)造函數(shù)入?yún)⑦M(jìn)行注釋?zhuān)?nbsp;   
        
    清單 15. 對(duì)構(gòu)造函數(shù)變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        private Car car;    
        private Office office;    
       
        @Autowired   
        public Boss(Car car , @Qualifier("office")Office office){    
            this.car = car;    
            this.office = office ;    
        }    
    }    
         
    @Qualifier 只能和 @Autowired 結(jié)合使用,是對(duì) @Autowired 有益的補(bǔ)充。一般來(lái)講,@Qualifier 對(duì)方法簽名中入?yún)⑦M(jìn)行注釋會(huì)降低代碼的可讀性,而對(duì)成員變量注釋則相對(duì)好一些。    
        
       
    使用 JSR-250 的注釋    
       
    Spring 不但支持自己定義的 @Autowired 的注釋?zhuān)€支持幾個(gè)由 JSR-250 規(guī)范定義的注釋?zhuān)鼈兎謩e是 @Resource、@PostConstruct 以及 @PreDestroy。    
       
    @Resource   
       
    @Resource 的作用相當(dāng)于 @Autowired,只不過(guò) @Autowired 按 byType 自動(dòng)注入,面 @Resource 默認(rèn)按 byName 自動(dòng)注入罷了。@Resource 有兩個(gè)屬性是比較重要的,分別是 name 和 type,Spring 將 @Resource 注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類(lèi)型。所以如果使用 name 屬性,則使用 byName 的自動(dòng)注入策略,而使用 type 屬性時(shí)則使用 byType 自動(dòng)注入策略。如果既不指定 name 也不指定 type 屬性,這時(shí)將通過(guò)反射機(jī)制使用 byName 自動(dòng)注入策略。    
       
    Resource 注釋類(lèi)位于 Spring 發(fā)布包的 lib/j2ee/common-annotations.jar 類(lèi)包中,因此在使用之前必須將其加入到項(xiàng)目的類(lèi)庫(kù)中。來(lái)看一個(gè)使用 @Resource 的例子:    
       
    清單 16. 使用 @Resource 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import javax.annotation.Resource;    
       
    public class Boss {    
        // 自動(dòng)注入類(lèi)型為 Car 的 Bean    
        @Resource   
        private Car car;    
       
        // 自動(dòng)注入 bean 名稱(chēng)為 office 的 Bean    
        @Resource(name = "office")    
        private Office office;    
    }    
         
    一般情況下,我們無(wú)需使用類(lèi)似于 @Resource(type=Car.class) 的注釋方式,因?yàn)?Bean 的類(lèi)型信息可以通過(guò) Java 反射從代碼中獲取。    
       
    要讓 JSR-250 的注釋生效,除了在 Bean 類(lèi)中標(biāo)注這些注釋外,還需要在 Spring 容器中注冊(cè)一個(gè)負(fù)責(zé)處理這些注釋的 BeanPostProcessor:    
       
    <bean     
      class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    
         
      
    CommonAnnotationBeanPostProcessor 實(shí)現(xiàn)了 BeanPostProcessor 接口,它負(fù)責(zé)掃描使用了 JSR-250 注釋的 Bean,并對(duì)它們進(jìn)行相應(yīng)的操作。    
       
    @PostConstruct 和 @PreDestroy   
       
    Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷(xiāo)毀前執(zhí)行特定的操作,您既可以通過(guò)實(shí)現(xiàn) InitializingBean/DisposableBean 接口來(lái)定制初始化之后 / 銷(xiāo)毀之前的操作方法,也可以通過(guò) <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷(xiāo)毀之前調(diào)用的操作方法。關(guān)于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業(yè)應(yīng)用開(kāi)發(fā)精解》第 3 章進(jìn)行了詳細(xì)的描述,有興趣的讀者可以查閱。    
       
    JSR-250 為初始化之后/銷(xiāo)毀之前方法的指定定義了兩個(gè)注釋類(lèi),分別是 @PostConstruct 和 @PreDestroy,這兩個(gè)注釋只能應(yīng)用于方法上。標(biāo)注了 @PostConstruct 注釋的方法將在類(lèi)實(shí)例化后調(diào)用,而標(biāo)注了 @PreDestroy 的方法將在類(lèi)銷(xiāo)毀之前調(diào)用。    
      
    清單 17. 使用 @PostConstruct 和 @PreDestroy 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import javax.annotation.Resource;    
    import javax.annotation.PostConstruct;    
    import javax.annotation.PreDestroy;    
       
    public class Boss {    
        @Resource   
        private Car car;    
       
        @Resource(name = "office")    
        private Office office;    
       
        @PostConstruct   
        public void postConstruct1(){    
            System.out.println("postConstruct1");    
        }    
       
        @PreDestroy   
        public void preDestroy1(){    
            System.out.println("preDestroy1");     
        }    
        …    
    }    
         
    您只需要在方法前標(biāo)注 @PostConstruct 或 @PreDestroy,這些方法就會(huì)在 Bean 初始化后或銷(xiāo)毀之前被 Spring 容器執(zhí)行了。    
       
    我 們知道,不管是通過(guò)實(shí)現(xiàn) InitializingBean/DisposableBean 接口,還是通過(guò) <bean> 元素的 init-method/destroy-method 屬性進(jìn)行配置,都只能為 Bean 指定一個(gè)初始化 / 銷(xiāo)毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個(gè)初始化 / 銷(xiāo)毀方法,那些被標(biāo)注 @PostConstruct 或 @PreDestroy 注釋的方法都會(huì)在初始化 / 銷(xiāo)毀時(shí)被執(zhí)行。    
       
    通過(guò)以下的測(cè)試代碼,您將可以看到 Bean 的初始化 / 銷(xiāo)毀方法是如何被執(zhí)行的:    
      
    清單 18. 測(cè)試類(lèi)代碼    
                        
    package com.baobaotao;    
       
    import org.springframework.context.support.ClassPathXmlApplicationContext;    
       
    public class AnnoIoCTest {    
       
        public static void main(String[] args) {    
            String[] locations = {"beans.xml"};    
            ClassPathXmlApplicationContext ctx =     
                new ClassPathXmlApplicationContext(locations);    
            Boss boss = (Boss) ctx.getBean("boss");    
            System.out.println(boss);    
            ctx.destroy();// 關(guān)閉 Spring 容器,以觸發(fā) Bean 銷(xiāo)毀方法的執(zhí)行    
        }    
    }    
         
       
    這 時(shí),您將看到標(biāo)注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動(dòng)時(shí),創(chuàng)建 Boss Bean 的時(shí)候被觸發(fā)執(zhí)行,而標(biāo)注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關(guān)閉前銷(xiāo)毀 Boss Bean 的時(shí)候被觸發(fā)執(zhí)行。    
           
    使用 <context:annotation-config/> 簡(jiǎn)化配置    
       
    Spring 2.1 添加了一個(gè)新的 context 的 Schema 命名空間,該命名空間對(duì)注釋驅(qū)動(dòng)、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會(huì)做任何事情的,它僅提供元數(shù)據(jù)信息。要使元數(shù) 據(jù)信息真正起作用,必須讓負(fù)責(zé)處理這些元數(shù)據(jù)的處理器工作起來(lái)。     
       
    而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數(shù)據(jù)的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊(cè)這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請(qǐng)看下面的配置:    
         
    清單 19. 調(diào)整 beans.xml 配置文件    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
         xmlns:context="http://www.springframework.org/schema/context"   
         xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
     http://www.springframework.org/schema/context     
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
         
        <context:annotation-config/>     
       
        <bean id="boss" class="com.baobaotao.Boss"/>    
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="001"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
          
    <context:annotationconfig/> 將隱式地向 Spring 容器注冊(cè) AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個(gè) BeanPostProcessor。    
       
    在配置文件中使用 context 命名空間之前,必須在 <beans> 元素中聲明 context 命名空間。    
       
        
    使用 @Component   
       
    雖 然我們可以通過(guò) @Autowired 或 @Resource 在 Bean 類(lèi)中使用自動(dòng)注入功能,但是 Bean 還是在 XML 文件中通過(guò) <bean> 進(jìn)行定義 —— 也就是說(shuō),在 XML 配置文件中定義 Bean,通過(guò) @Autowired 或 @Resource 為 Bean 的成員變量、方法入?yún)⒒驑?gòu)造函數(shù)入?yún)⑻峁┳詣?dòng)注入的功能。能否也通過(guò)注釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過(guò) Spring 2.5 提供的 @Component 注釋就可以達(dá)到這個(gè)目標(biāo)了。    
       
    下面,我們完全使用注釋定義 Bean 并完成 Bean 之間裝配:    
       
       
    清單 20. 使用 @Component 注釋的 Car.java    
                        
    package com.baobaotao;    
       
    import org.springframework.stereotype.Component;    
       
    @Component   
    public class Car {    
        …    
    }    
         
         
    僅需要在類(lèi)定義處,使用 @Component 注釋就可以將一個(gè)類(lèi)定義了 Spring 容器中的 Bean。下面的代碼將 Office 定義為一個(gè) Bean:    
        
    清單 21. 使用 @Component 注釋的 Office.java    
                        
    package com.baobaotao;    
       
    import org.springframework.stereotype.Component;    
       
    @Component   
    public class Office {    
        private String officeNo = "001";    
        …    
    }    
         
    這樣,我們就可以在 Boss 類(lèi)中通過(guò) @Autowired 注入前面定義的 Car 和 Office Bean 了。    
       
    清單 22. 使用 @Component 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import org.springframework.beans.factory.annotation.Autowired;    
    import org.springframework.beans.factory.annotation.Required;    
    import org.springframework.beans.factory.annotation.Qualifier;    
    import org.springframework.stereotype.Component;    
       
    @Component("boss")    
    public class Boss {    
        @Autowired   
        private Car car;    
       
        @Autowired   
        private Office office;    
        …    
    }    
        
    @Component 有一個(gè)可選的入?yún)ⅲ糜谥付?Bean 的名稱(chēng),在 Boss 中,我們就將 Bean 名稱(chēng)定義為“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過(guò) byType 策略就可以自動(dòng)注入了,所以大可不必指定 Bean 的名稱(chēng)。    
       
    在使用 @Component 注釋后,Spring 容器必須啟用類(lèi)掃描機(jī)制以啟用注釋驅(qū)動(dòng) Bean 定義和注釋驅(qū)動(dòng) Bean 自動(dòng)注入的策略。Spring 2.5 對(duì) context 命名空間進(jìn)行了擴(kuò)展,提供了這一功能,請(qǐng)看下面的配置:    
        
    清單 23. 簡(jiǎn)化版的 beans.xml    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xmlns:context="http://www.springframework.org/schema/context"   
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
     http://www.springframework.org/schema/context     
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
        <context:component-scan base-package="com.baobaotao"/>    
    </beans>    
          
    這 里,所有通過(guò) <bean> 元素定義 Bean 的配置內(nèi)容已經(jīng)被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問(wèn)題了——Spring XML 配置文件得到了極致的簡(jiǎn)化(當(dāng)然配置元數(shù)據(jù)還是需要的,只不過(guò)以注釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類(lèi)包,類(lèi)包及其遞歸子包中所有的類(lèi)都會(huì)被處理。    
       
    <context:component-scan/> 還允許定義過(guò)濾器將基包下的某些類(lèi)納入或排除。Spring 支持以下 4 種類(lèi)型的過(guò)濾方式,通過(guò)下表說(shuō)明:    
       
    表 1. 掃描過(guò)濾方式    
    過(guò)濾器類(lèi)型 說(shuō)明     
    注釋 假如 com.baobaotao.SomeAnnotation 是一個(gè)注釋類(lèi),我們可以將使用該注釋的類(lèi)過(guò)濾出來(lái)。     
    類(lèi)名指定 通過(guò)全限定類(lèi)名進(jìn)行過(guò)濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。     
    正則表達(dá)式 通過(guò)正則表達(dá)式定義過(guò)濾的類(lèi),如下所示: com\.baobaotao\.Default.*     
    AspectJ 表達(dá)式 通過(guò) AspectJ 表達(dá)式定義過(guò)濾的類(lèi),如下所示: com. baobaotao..*Service+     
       
    下面是一個(gè)簡(jiǎn)單的例子:    
       
    <context:component-scan base-package="com.baobaotao">    
        <context:include-filter type="regex"     
            expression="com\.baobaotao\.service\..*"/>    
        <context:exclude-filter type="aspectj"     
            expression="com.baobaotao.util..*"/>    
    </context:component-scan>    
          
    值 得注意的是 <context:component-scan/> 配置項(xiàng)不但啟用了對(duì)類(lèi)包進(jìn)行掃描以實(shí)施注釋驅(qū)動(dòng) Bean 定義的功能,同時(shí)還啟用了注釋驅(qū)動(dòng)自動(dòng)注入的功能(即還隱式地在內(nèi)部注冊(cè)了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),因此當(dāng)使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了。    
       
    默認(rèn)情況下通過(guò) @Component 定義的 Bean 都是 singleton 的,如果需要使用其它作用范圍的 Bean,可以通過(guò) @Scope 注釋來(lái)達(dá)到目標(biāo),如以下代碼所示:    
       
    清單 24. 通過(guò) @Scope 指定 Bean 的作用范圍    
                        
    package com.baobaotao;    
    import org.springframework.context.annotation.Scope;    
    …    
    @Scope("prototype")    
    @Component("boss")    
    public class Boss {    
        …    
    }    
         
    這樣,當(dāng)從 Spring 容器中獲取 boss Bean 時(shí),每次返回的都是新的實(shí)例了。    
          
    采用具有特殊語(yǔ)義的注釋    
       
    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個(gè)擁有特殊語(yǔ)義的注釋?zhuān)鼈兎謩e是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個(gè)注釋和 @Component 是等效的,但是從注釋類(lèi)的命名上,很容易看出這 3 個(gè)注釋分別和持久層、業(yè)務(wù)層和控制層(Web 層)相對(duì)應(yīng)。雖然目前這 3 個(gè)注釋和 @Component 相比沒(méi)有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應(yīng)用程序采用了經(jīng)典的三層分層結(jié)構(gòu)的話,最好在持久層、業(yè)務(wù)層和控制層分別采用 @Repository、@Service 和 @Controller 對(duì)分層中的類(lèi)進(jìn)行注釋?zhuān)?@Component 對(duì)那些比較中立的類(lèi)進(jìn)行注釋。    
            
    注釋配置和 XML 配置的適用場(chǎng)合    
       
    是否有了這些 IOC 注釋?zhuān)覀兙涂梢酝耆鸪瓉?lái) XML 配置的方式呢?答案是否定的。有以下幾點(diǎn)原因:    
       
    注 釋配置不一定在先天上優(yōu)于 XML 配置。如果 Bean 的依賴(lài)關(guān)系是固定的,(如 Service 使用了哪幾個(gè) DAO 類(lèi)),這種配置信息不會(huì)在部署時(shí)發(fā)生調(diào)整,那么注釋配置優(yōu)于 XML 配置;反之如果這種依賴(lài)關(guān)系會(huì)在部署時(shí)發(fā)生調(diào)整,XML 配置顯然又優(yōu)于注釋配置,因?yàn)樽⑨屖菍?duì) Java 源代碼的調(diào)整,您需要重新改寫(xiě)源代碼并重新編譯才可以實(shí)施調(diào)整。     
    如果 Bean 不是自己編寫(xiě)的類(lèi)(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無(wú)法實(shí)施,此時(shí) XML 配置是唯一可用的方式。     
    注釋配置往往是類(lèi)級(jí)別的,而 XML 配置則可以表現(xiàn)得更加靈活。比如相比于 @Transaction 事務(wù)注釋?zhuān)褂?aop/tx 命名空間的事務(wù)配置更加靈活和簡(jiǎn)單。     
    所 以在實(shí)現(xiàn)應(yīng)用中,我們往往需要同時(shí)使用注釋配置和 XML 配置,對(duì)于類(lèi)級(jí)別且不會(huì)發(fā)生變動(dòng)的配置可以?xún)?yōu)先考慮注釋配置;而對(duì)于那些第三方類(lèi)以及容易發(fā)生調(diào)整的配置則應(yīng)優(yōu)先考慮使用 XML 配置。Spring 會(huì)在具體實(shí)施 Bean 創(chuàng)建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。    
           
    小結(jié)    
       
    Spring 在 2.1 以后對(duì)注釋配置提供了強(qiáng)力的支持,注釋配置功能成為 Spring 2.5 的最大的亮點(diǎn)之一。合理地使用 Spring 2.5 的注釋配置,可以有效減少配置的工作量,提高程序的內(nèi)聚性。但是這并不意味著傳統(tǒng) XML 配置將走向消亡,在第三方類(lèi) Bean 的配置,以及那些諸如數(shù)據(jù)源、緩存池、持久層操作模板類(lèi)、事務(wù)管理等內(nèi)容的配置上,XML 配置依然擁有不可替代的地位。

    posted @ 2011-10-10 15:49 AK47 閱讀(330) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼)數(shù)據(jù)庫(kù)三范式經(jīng)典實(shí)例解析

    數(shù)據(jù)庫(kù)的設(shè)計(jì)范式是數(shù)據(jù)庫(kù)設(shè)計(jì)所需要滿(mǎn)足的規(guī)范,滿(mǎn)足這些規(guī)范的數(shù)據(jù)庫(kù)是簡(jiǎn)潔的、結(jié)構(gòu)明晰的,同時(shí),不會(huì)發(fā)生插入(insert)、刪除(delete)和更新(update)操作異常。反之則是亂七八糟,不僅給數(shù)據(jù)庫(kù)的編程人員制造麻煩,而且面目可憎,可能存儲(chǔ)了大量不需要的冗余信息。
         設(shè)計(jì)范式是不是很難懂呢?非也,大學(xué)教材上給我們一堆數(shù)學(xué)公式我們當(dāng)然看不懂,也記不住。所以我們很多人就根本不按照范式來(lái)設(shè)計(jì)數(shù)據(jù)庫(kù)。
         實(shí)質(zhì)上,設(shè)計(jì)范式用很形象、很簡(jiǎn)潔的話語(yǔ)就能說(shuō)清楚,道明白。本文將對(duì)范式進(jìn)行通俗地說(shuō)明,并以筆者曾經(jīng)設(shè)計(jì)的一個(gè)簡(jiǎn)單論壇的數(shù)據(jù)庫(kù)為例來(lái)講解怎樣將這些范式應(yīng)用于實(shí)際工程。

    范式說(shuō)明
         第一范式(1NF):數(shù)據(jù)庫(kù)表中的字段都是單一屬性的,不可再分。這個(gè)單一屬性由基本類(lèi)型構(gòu)成,包括整型、實(shí)數(shù)、字符型、邏輯型、日期型等。
         例如,如下的數(shù)據(jù)庫(kù)表是符合第一范式:

    字段1 字段2 字段3 字段4
    ? ? ? ?
     而這樣的數(shù)據(jù)庫(kù)表是不符合第一范式的:
    字段1 字段2 字段3 字段4
    ? ? 字段3.1 字段3.2 ?

     

         很顯然,在當(dāng)前的任何關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)中,傻瓜也不可能做出不符合第一范式的數(shù)據(jù)庫(kù),因?yàn)檫@些DBMS不允許你把數(shù)據(jù)庫(kù)表的一列再分成二列或多列。因此,你想在現(xiàn)有的DBMS中設(shè)計(jì)出不符合第一范式的數(shù)據(jù)庫(kù)都是不可能的。
         第二范式(2NF):數(shù)據(jù)庫(kù)表中不存在非關(guān)鍵字段對(duì)任一候選關(guān)鍵字段的部分函數(shù)依賴(lài)(部分函數(shù)依賴(lài)指的是存在組合關(guān)鍵字中的某些字段決定非關(guān)鍵字段的情況),也即所有非關(guān)鍵字段都完全依賴(lài)于任意一組候選關(guān)鍵字。
         假定選課關(guān)系表為SelectCourse(學(xué)號(hào), 姓名, 年齡, 課程名稱(chēng), 成績(jī), 學(xué)分),關(guān)鍵字為組合關(guān)鍵字(學(xué)號(hào), 課程名稱(chēng)),因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (學(xué)號(hào), 課程名稱(chēng)) → (姓名, 年齡, 成績(jī), 學(xué)分)
         這個(gè)數(shù)據(jù)庫(kù)表不滿(mǎn)足第二范式,因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (課程名稱(chēng)) → (學(xué)分)
         (學(xué)號(hào)) → (姓名, 年齡)
    即存在組合關(guān)鍵字中的字段決定非關(guān)鍵字的情況。
         由于不符合2NF,這個(gè)選課關(guān)系表會(huì)存在如下問(wèn)題:
         (1) 數(shù)據(jù)冗余:
         同一門(mén)課程由n個(gè)學(xué)生選修,"學(xué)分"就重復(fù)n-1次;同一個(gè)學(xué)生選修了m門(mén)課程,姓名和年齡就重復(fù)了m-1次。
         (2) 更新異常:
         若調(diào)整了某門(mén)課程的學(xué)分,數(shù)據(jù)表中所有行的"學(xué)分"值都要更新,否則會(huì)出現(xiàn)同一門(mén)課程學(xué)分不同的情況。
         (3) 插入異常:
         假設(shè)要開(kāi)設(shè)一門(mén)新的課程,暫時(shí)還沒(méi)有人選修。這樣,由于還沒(méi)有"學(xué)號(hào)"關(guān)鍵字,課程名稱(chēng)和學(xué)分也無(wú)法記錄入數(shù)據(jù)庫(kù)。
         (4) 刪除異常:
         假設(shè)一批學(xué)生已經(jīng)完成課程的選修,這些選修記錄就應(yīng)該從數(shù)據(jù)庫(kù)表中刪除。但是,與此同時(shí),課程名稱(chēng)和學(xué)分信息也被刪除了。很顯然,這也會(huì)導(dǎo)致插入異常。

         把選課關(guān)系表SelectCourse改為如下三個(gè)表:
         學(xué)生:Student(學(xué)號(hào), 姓名, 年齡);
         課程:Course(課程名稱(chēng), 學(xué)分);
         選課關(guān)系:SelectCourse(學(xué)號(hào), 課程名稱(chēng), 成績(jī))。
         這樣的數(shù)據(jù)庫(kù)表是符合第二范式的,消除了數(shù)據(jù)冗余、更新異常、插入異常和刪除異常。
         另外,所有單關(guān)鍵字的數(shù)據(jù)庫(kù)表都符合第二范式,因?yàn)椴豢赡艽嬖诮M合關(guān)鍵字。
         第三范式(3NF):在第二范式的基礎(chǔ)上,數(shù)據(jù)表中如果不存在非關(guān)鍵字段對(duì)任一候選關(guān)鍵字段的傳遞函數(shù)依賴(lài)則符合第三范式。所謂傳遞函數(shù)依賴(lài),指的是如果存在"A → B → C"的決定關(guān)系,則C傳遞函數(shù)依賴(lài)于A。因此,滿(mǎn)足第三范式的數(shù)據(jù)庫(kù)表應(yīng)該不存在如下依賴(lài)關(guān)系:
         關(guān)鍵字段 → 非關(guān)鍵字段x → 非關(guān)鍵字段y
         假定學(xué)生關(guān)系表為Student(學(xué)號(hào), 姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話),關(guān)鍵字為單一關(guān)鍵字"學(xué)號(hào)",因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (學(xué)號(hào)) → (姓名, 年齡, 所在學(xué)院, 學(xué)院地點(diǎn), 學(xué)院電話)
    這個(gè)數(shù)據(jù)庫(kù)是符合2NF的,但是不符合3NF,因?yàn)榇嬖谌缦聸Q定關(guān)系:
         (學(xué)號(hào)) → (所在學(xué)院) → (學(xué)院地點(diǎn), 學(xué)院電話)
    即存在非關(guān)鍵字段"學(xué)院地點(diǎn)"、"學(xué)院電話"對(duì)關(guān)鍵字段"學(xué)號(hào)"的傳遞函數(shù)依賴(lài)。
         它也會(huì)存在數(shù)據(jù)冗余、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
         把學(xué)生關(guān)系表分為如下兩個(gè)表:
         學(xué)生:(學(xué)號(hào), 姓名, 年齡, 所在學(xué)院);
         學(xué)院:(學(xué)院, 地點(diǎn), 電話)。
    這樣的數(shù)據(jù)庫(kù)表是符合第三范式的,消除了數(shù)據(jù)冗余、更新異常、插入異常和刪除異常。
         鮑依斯-科得范式(BCNF):在第三范式的基礎(chǔ)上,數(shù)據(jù)庫(kù)表中如果不存在任何字段對(duì)任一候選關(guān)鍵字段的傳遞函數(shù)依賴(lài)則符合第三范式。
         假設(shè)倉(cāng)庫(kù)管理關(guān)系表為StorehouseManage(倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID, 管理員ID, 數(shù)量),且有一個(gè)管理員只在一個(gè)倉(cāng)庫(kù)工作;一個(gè)倉(cāng)庫(kù)可以存儲(chǔ)多種物品。這個(gè)數(shù)據(jù)庫(kù)表中存在如下決定關(guān)系:
         (倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID) →(管理員ID, 數(shù)量)
         (管理員ID, 存儲(chǔ)物品ID) → (倉(cāng)庫(kù)ID, 數(shù)量)
         所以,(倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID)和(管理員ID, 存儲(chǔ)物品ID)都是StorehouseManage的候選關(guān)鍵字,表中的唯一非關(guān)鍵字段為數(shù)量,它是符合第三范式的。但是,由于存在如下決定關(guān)系:
         (倉(cāng)庫(kù)ID) → (管理員ID)
         (管理員ID) → (倉(cāng)庫(kù)ID)
    即存在關(guān)鍵字段決定關(guān)鍵字段的情況,所以其不符合 BCNF范式。它會(huì)出現(xiàn)如下異常情況:
         (1) 刪除異常:
         當(dāng)倉(cāng)庫(kù)被清空后,所有"存儲(chǔ)物品ID"和"數(shù)量"信息被刪除的同時(shí),"倉(cāng)庫(kù)ID"和"管理員ID"信息也被刪除了。
         (2) 插入異常:
         當(dāng)倉(cāng)庫(kù)沒(méi)有存儲(chǔ)任何物品時(shí),無(wú)法給倉(cāng)庫(kù)分配管理員。
         (3) 更新異常:
         如果倉(cāng)庫(kù)換了管理員,則表中所有行的管理員ID都要修改。
         把倉(cāng)庫(kù)管理關(guān)系表分解為二個(gè)關(guān)系表:
         倉(cāng)庫(kù)管理:StorehouseManage(倉(cāng)庫(kù)ID, 管理員ID);
         倉(cāng)庫(kù):Storehouse(倉(cāng)庫(kù)ID, 存儲(chǔ)物品ID, 數(shù)量)。
         這樣的數(shù)據(jù)庫(kù)表是符合BCNF范式的,消除了刪除異常、插入異常和更新異常。


    原帖地址: http://www.cublog.cn/u/23975/showart.php?id=391210

    posted @ 2011-02-21 14:45 AK47 閱讀(321) | 評(píng)論 (0)編輯 收藏

    Hibernate 實(shí)體對(duì)象的生命周期匯總

    本帖匯總了網(wǎng)上幾篇關(guān)于hibernate的生命周期的帖子。

    轉(zhuǎn)載:

    實(shí)體對(duì)象的生命周期在Hibernate應(yīng)用中是一個(gè)很關(guān)鍵的概念,正確的理解實(shí)體對(duì)象的生命周期將對(duì)我們應(yīng)用Hibernate做持久層設(shè)計(jì)起到很大的作用.而所謂的實(shí)體對(duì)象的生命周期就是指實(shí)體對(duì)象由產(chǎn)生到被GC回收的一段過(guò)程.在這過(guò)程中我們需要理解的就是實(shí)體對(duì)象生命周期中的三種狀態(tài).

    1. 自由狀態(tài)(Transient)
    所謂的Transient狀態(tài),即實(shí)體對(duì)象在內(nèi)存中自由存在,與數(shù)據(jù)庫(kù)中的記錄無(wú)關(guān),通常是我們的J2EE中 VO,并沒(méi)有被納入Hibernate的實(shí)體管理容器.

    1    Test test = new Test();
    2        test.setName("energykk");
    3        //此時(shí)的test對(duì)象處于Transient(自由狀態(tài))并沒(méi)有被Hibernate框架所管理
    4        

    2.持久狀態(tài)(Persistent)
    何謂 Persistent? 即實(shí)體對(duì)象已經(jīng)處于被Hibernate實(shí)體管理容器容器所管理的狀態(tài).這種狀態(tài)下這個(gè)實(shí)體對(duì)象的引用將被納入Hibernate實(shí)體管理容器容器所管理.
    處于Persistent狀態(tài)的實(shí)體對(duì)象,對(duì)它的變更也將被固化到數(shù)據(jù)庫(kù)中.
    在J2EE中通常指的是一個(gè)PO.
    Transaction tr = session.beginTransaction();
            session.save(test);
            
    //此時(shí)的test對(duì)象已經(jīng)處于Persistent(持久狀態(tài))它被Hibernate 納入實(shí)體管理容器
            tr.commit();
            Transaction tr2 
    = session.beginTransaction();
            test.setName(
    "xukai");
            
    //在這個(gè)事務(wù)中我們并沒(méi)有顯示的調(diào)用save()方法但是由于Persistent狀態(tài)的對(duì)象將會(huì)自動(dòng)的固化到
            
    //數(shù)據(jù)庫(kù)中,因此此時(shí)正處在Persistent狀態(tài)的test對(duì)象的變化也將自動(dòng)被同步到數(shù)據(jù)庫(kù)中
            tr2.commit();

    處于Persistent狀態(tài)的實(shí)體可以簡(jiǎn)單的理解為:如果一個(gè)實(shí)體對(duì)象與session發(fā)生了關(guān)聯(lián),并且處于session的有效期內(nèi),那么這個(gè)實(shí)體對(duì)象就處于Persistent狀態(tài).

    3.游離狀態(tài)(Detached)
    處于Persistent狀態(tài)的實(shí)體對(duì)象,其對(duì)應(yīng)的session關(guān)閉以后,那么這個(gè)實(shí)體就處于 Detached狀態(tài).
    我們可以認(rèn)為session對(duì)象就是一個(gè)Persistent的宿主,一旦這個(gè)宿主失效,那么這個(gè)實(shí)體就處于 Detached狀態(tài).

    session.close();
            
    //與test對(duì)象關(guān)聯(lián)的session被關(guān)閉,因此此時(shí)的test對(duì)象進(jìn)入 Detached(游離狀態(tài))
            
            session2 
    = HibernateSessionFactory.getSession();
            Transaction tr3 
    = session2.beginTransaction();
            session2.update(test);
            
    //此時(shí)正處于Detached狀態(tài)的test對(duì)象由于再次借助與session2被納入到Hibernate的實(shí)體管理容器所以此時(shí)的
            
    //test對(duì)象恢復(fù)到Persistent狀態(tài)
            test.setName("jjjj");
            tr3.commit();
            
            session2.close();

    既然Transient狀態(tài)的實(shí)體與Detached狀態(tài)的實(shí)體都與Hibernate的實(shí)體管理容器沒(méi)有關(guān)系,那他們到底存在哪些差異?
    差異就在于處于Transient狀態(tài)的只有一個(gè)Name的屬性.此時(shí)的test對(duì)象所包含的數(shù)據(jù)信息僅限于此,他與數(shù)據(jù)庫(kù)中的記錄沒(méi)有任何瓜葛.
    但是處于Detached狀態(tài)的實(shí)體已經(jīng)不止包含Name這個(gè)屬性,還被賦予了主鍵也就是通常POJO里的id屬性,由于id是主鍵,他可以確定數(shù)據(jù)庫(kù)表中的一條
    唯一的記錄,那么自然的處于Detached狀態(tài)的實(shí)體就能與數(shù)據(jù)庫(kù)表中擁有相同id的記錄相關(guān)聯(lián).
    這就是他們之間所存在的差異, 簡(jiǎn)而言之,Transient狀態(tài)的實(shí)體缺乏與數(shù)據(jù)庫(kù)表記錄之間的聯(lián)系,而Detached狀態(tài)的試題恰恰相反.只不過(guò)是脫離了session這個(gè)數(shù)據(jù)庫(kù)操作平臺(tái)而已.
    原帖地址 : http://www.tkk7.com/energykk/archive/2007/05/08/115927.html

     生命周期圖:
    原圖地址:http://hi.baidu.com/quest2run/blog/item/39e1d08c7dbd45f4503d9222.html
     

    persistence context



    生命周期特征總結(jié) :
    原帖地址 : http://blog.csdn.net/hgd250/archive/2008/08/06/2775943.aspx
    Transient:

        與數(shù)據(jù)庫(kù)中的記錄沒(méi)有任何關(guān)系,即沒(méi)有與其相關(guān)聯(lián)的數(shù)據(jù)庫(kù)記錄.
        與session沒(méi)有任何關(guān)系.即沒(méi)有通過(guò)session對(duì)象的實(shí)例對(duì)其進(jìn)行任何持久化的操作
    Persistent:
        每個(gè)persistent狀態(tài)的實(shí)體對(duì)象都與一個(gè)session對(duì)象的實(shí)例相關(guān)聯(lián)
        處于 Persistent狀態(tài)的實(shí)體對(duì)象是與數(shù)據(jù)庫(kù)中的記錄相關(guān)聯(lián)的.
        Hibernate會(huì)依據(jù)persistent狀態(tài)的實(shí)體對(duì)象的屬性變化而改變數(shù)據(jù)庫(kù)中相對(duì)應(yīng)的記錄
    .
    Detached:
        游離態(tài)是由持久態(tài)實(shí)體對(duì)象轉(zhuǎn)變而來(lái)的.
        游離態(tài)實(shí)體不再與session對(duì)象相關(guān)聯(lián).
        游離態(tài)實(shí)體對(duì)象與數(shù)據(jù)庫(kù)中的記錄沒(méi)有直接聯(lián)系,對(duì)其所做的任何修改將不會(huì)影響到到數(shù)據(jù)庫(kù)中的數(shù)據(jù).
        游離態(tài)實(shí)體對(duì)象在數(shù)據(jù)庫(kù)有相對(duì)應(yīng)的數(shù)據(jù)記錄,如果沒(méi)有被其他事務(wù)刪除.

    posted @ 2011-02-14 14:26 AK47 閱讀(333) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼)BigInteger 和 BigDecimal

    高精度數(shù)字
    Java 提供了兩個(gè)類(lèi)專(zhuān)門(mén)用于進(jìn)行高精度運(yùn)算BigInteger 和 BigDecimal ,盡管它們可大致劃分到與封裝器相同的類(lèi)別里,但兩者都沒(méi)有對(duì)應(yīng)的主類(lèi)型;這兩個(gè)類(lèi)都有自己的一系列方法,類(lèi)似于我們針對(duì)主類(lèi)型執(zhí)行的操作,也就是說(shuō)能用 int 或float 做的事情,用BigInteger和BigDecimal 一樣可以做,只是必須換用方法調(diào)用,而不是使用運(yùn)算符。此外由于牽涉更多,所以運(yùn)算速度會(huì)慢一點(diǎn)總之我們犧牲了速度,但換來(lái)了精度。

    高精度浮點(diǎn)數(shù)BigDecimal

    一些非整數(shù)值(如幾美元和幾美分這樣的小數(shù))需要很精確。浮點(diǎn)數(shù)不是精確值,所以使用它們會(huì)導(dǎo)致舍入誤差。因此,使用浮點(diǎn)數(shù)來(lái)試圖表示象貨幣量這樣的精確數(shù)量不是一個(gè)好的想法。使用浮點(diǎn)數(shù)來(lái)進(jìn)行美元和美分計(jì)算會(huì)得到災(zāi)難性的后果。浮點(diǎn)數(shù)最好用來(lái)表示象測(cè)量值這類(lèi)數(shù)值,這類(lèi)值從一開(kāi)始就不怎么精確。
        從 JDK 1.3 起,Java 開(kāi)發(fā)人員就有了另一種數(shù)值表示法來(lái)表示非整數(shù):BigDecimal。BigDecimal 是標(biāo)準(zhǔn)的類(lèi),在編譯器中不需要特殊支持,它可以表示任意精度的小數(shù),并對(duì)它們進(jìn)行計(jì)算。在內(nèi)部,可以用任意精度任何范圍的值和一個(gè)換算因子來(lái)表示 BigDecimal,換算因子表示左移小數(shù)點(diǎn)多少位,從而得到所期望范圍內(nèi)的值。因此,用 BigDecimal 表示的數(shù)的形式為 unscaledValue*10-scale。
    用于加、減、乘和除的方法給  BigDecimal 值提供了算術(shù)運(yùn)算。由于 BigDecimal 對(duì)象是不可變的,這些方法中的每一個(gè)都會(huì)產(chǎn)生新的 BigDecimal 對(duì)象。因此,因?yàn)閯?chuàng)建對(duì)象的開(kāi)銷(xiāo),BigDecimal 不適合于大量的數(shù)學(xué)計(jì)算,但設(shè)計(jì)它的目的是用來(lái)精確地表示小數(shù)。如果您正在尋找一種能精確表示如貨幣量這樣的數(shù)值,則 BigDecimal 可以很好地勝任該任務(wù)。
    如浮點(diǎn)類(lèi)型一樣,BigDecimal 也有一些令人奇怪的行為。尤其在使用 equals() 方法來(lái)檢測(cè)數(shù)值之間是否相等時(shí)要小心。equals() 方法認(rèn)為,兩個(gè)表示同一個(gè)數(shù)但換算值不同(例如,100.00 和  100.000)的 BigDecimal 值是不相等的。然而,compareTo() 方法會(huì)認(rèn)為這兩個(gè)數(shù)是相等的,所以在從數(shù)值上比較兩個(gè)  BigDecimal 值時(shí),應(yīng)該使用 compareTo() 而不是 equals()。
    另外還有一些情形,任意精度的小數(shù)運(yùn)算仍不能表示精確結(jié)果。例如,1 除以 9 會(huì)產(chǎn)生無(wú)限循環(huán)的小數(shù) .111111...。出于這個(gè)原因,在進(jìn)行除法運(yùn)算時(shí),BigDecimal 可以讓您顯式地控制舍入。movePointLeft() 方法支持 10 的冪次方的精確除法。
    對(duì)于 BigDecimal,有幾個(gè)可用的構(gòu)造函數(shù)。其中一個(gè)構(gòu)造函數(shù)以雙精度浮點(diǎn)數(shù)作為輸入,另一個(gè)以整數(shù)和換算因子作為輸入,還有一個(gè)以小數(shù)的 String 表示作為輸入。要小心使用  BigDecimal(double) 構(gòu)造函數(shù), 因?yàn)槿绻涣私馑瑫?huì)在計(jì)算過(guò)程中產(chǎn)生舍入誤差。請(qǐng)使用基于整數(shù)或 String 的構(gòu)造函數(shù)。
    如果使用 BigDecimal(double) 構(gòu)造函數(shù)不恰當(dāng),在傳遞給 JDBC setBigDecimal() 方法時(shí),會(huì)造成似乎很奇怪的 JDBC 驅(qū)動(dòng)程序中的異常。例如,考慮以下 JDBC 代碼,該代碼希望將數(shù)字 0.01 存儲(chǔ)到小數(shù)字段:
      PreparedStatement ps =connection.prepareStatement("INSERT INTO Foo SET name=?, value=?");
      ps.setString(1, "penny");
      ps.setBigDecimal(2, new BigDecimal(0.01));
      ps.executeUpdate();
         在執(zhí)行這段似乎無(wú)害的代碼時(shí)會(huì)拋出一些令人迷惑不解的異常(這取決于具體的 JDBC 驅(qū)動(dòng)程序),因?yàn)?0.01 的雙精度近似值會(huì)導(dǎo)致大的換算值,這可能會(huì)使 JDBC 驅(qū)動(dòng)程序或數(shù)據(jù)庫(kù)感到迷惑。JDBC 驅(qū)動(dòng)程序會(huì)產(chǎn)生異常,但可能不會(huì)說(shuō)明代碼實(shí)際上錯(cuò)在哪里,除非意識(shí)到二進(jìn)制浮點(diǎn)數(shù)的局限性。相反,使用 BigDecimal("0.01") 或 BigDecimal(1, 2) 構(gòu)造 BigDecimal 來(lái)避免這類(lèi)問(wèn)題, 因?yàn)檫@兩種方法都可以精確地表示小數(shù)。
     

    code :

    import java.math.BigDecimal;
    /** * *
    * <p>Title: 開(kāi)源,開(kāi)放</p>
    * * <p>Description: opeansource</p>
    * * <p>Copyright: Copyright (c) 2004</p>
    * * <p>Company: ?海棠</p>
    * * @author HaiTang Ming
    * * @version 1.0 */
    public class BigDecimalUtil { 
    //默認(rèn)除法運(yùn)算精度,及即保留小數(shù)點(diǎn)多少位 
    private static final int DEF_DIV_SCALE = 2; 
    //這個(gè)類(lèi)不能實(shí)例化 
    private BigDecimalUtil (){   } 
    /**   
      * * 提供精確的加法運(yùn)算。   
      * * @param v1 被加數(shù)   
      * * @param v2 加數(shù)   
      * * @return 兩個(gè)參數(shù)的和   
      * */ 
    public static double add(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.add(b2)).doubleValue(); 

    /**

      *提供精確的減法運(yùn)算。 
      * * @param v1 被減數(shù) 
      * * @param v2 減數(shù) 
      * * @return 兩個(gè)參數(shù)的差
      **/ 
    public static double sub(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.subtract(b2)).doubleValue(); 

    /**   
      * * 提供精確的乘法運(yùn)算。   
      * * @param v1 被乘數(shù)   
      * * @param v2 乘數(shù)   
      * * @return 兩個(gè)參數(shù)的積   
      * */
    public static double mul(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.multiply(b2)).doubleValue(); 

    /**   
      * * 提供(相對(duì))精確的除法運(yùn)算,當(dāng)發(fā)生除不盡的情況時(shí),精確到   
      * * 小數(shù)點(diǎn)以后多少位,以后的數(shù)字四舍五入。   
      * * @param v1 被除數(shù)   
      * * @param v2 除數(shù)   
      * * @return 兩個(gè)參數(shù)的商   
      * */ 
    public static double div(double v1,double v2){   
      return div(v1,v2,DEF_DIV_SCALE); 

    /**   
      * * 提供(相對(duì))精確的除法運(yùn)算。當(dāng)發(fā)生除不盡的情況時(shí),由scale參數(shù)指   
      * * 定精度,以后的數(shù)字四舍五入。   
      * * @param v1 被除數(shù) 
      * @param v2 除數(shù)   
      * * @param scale 表示表示需要精確到小數(shù)點(diǎn)以后幾位。   
      * * @return 兩個(gè)參數(shù)的商   
      * */ 
    public static double div(double v1,double v2,int scale){   
      if(scale<0){     
       throw new IllegalArgumentException("The scale must be a positive integer or zero");   
      }   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP)).doubleValue(); 

    /**   
      * * 提供精確的小數(shù)位四舍五入處理。   
      * * @param v 需要四舍五入的數(shù)字   
      * * @param scale 小數(shù)點(diǎn)后保留幾位   
      * * @return 四舍五入后的結(jié)果   
      * */ 
    public static double round(double v,int scale){ 
      if(scale<0){     
       throw new IllegalArgumentException("The scale must be a positive integer or zero");
      }   
      BigDecimal b = new BigDecimal(Double.toString(v));   
      BigDecimal one = new BigDecimal("1");   
      return (b.divide(one,scale,BigDecimal.ROUND_HALF_UP)).doubleValue(); 
    }   
    public static void main(String[] args){   
      System.out.println(add(234.44,534.90));
     
      double a = 123.345678;   
      double d = round(a,2);   
      System.out.println("round("+a+",2)--->"+d); 
    }
    }

    高精度整數(shù)BigInteger

    BigInteger支持任意精度的整數(shù),也就是說(shuō)我們可精確表示任意大小的整數(shù)值;同時(shí)在運(yùn)算過(guò)程中不會(huì)丟失任何信息;
    在BigInteger類(lèi)中有所有的基本算術(shù)運(yùn)算方法,如加、減、乘、除,以及可能會(huì)用到的位運(yùn)算如或、異或、非、左移、右移等。下面是一些方法的例子:當(dāng)然,如果要有更多的使用方法,可以查閱java api 。

    code :public class BigIntegerTest { 
    public BigIntegerTest() {   } 
    /**   
      * * 測(cè)試BigInteger
      * */ 
    public static void testBigInteger() {   
      BigInteger bi = new BigInteger("888");   
      //multiply :乘法   
      BigInteger result = bi.multiply(new BigInteger("2"));   
      System.out.println(result);   
      //divide : 除法   
      result = bi.divide(new BigInteger("2"));   
      System.out.println(result);   
      //add : 加法   
      result = bi.add(new BigInteger("232"));   
      System.out.println(result);   
      //subtract :減法   
      result = bi.subtract(new BigInteger("23122"));   
      System.out.println(result);   
      result = bi.shiftRight(2);   
      System.out.println(result); 
    }   
    public static void main(String[] args) {   
      testBigInteger(); 
    }
    }
    原貼地址http://dev.firnow.com/course/3_program/java/javaxl/2008914 /142796_2.html

    posted @ 2010-12-10 14:16 AK47 閱讀(1028) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼) 超大整數(shù)相加,超過(guò)了long的范圍,你要怎么做!

     

    引用:

     這個(gè)只能夠用字符串的形式來(lái)處理了,因?yàn)橛?jì)算機(jī)能夠處理的最大是long型,本文以字符串的形式來(lái)進(jìn)行超大數(shù)據(jù)的相加,理論上只要你的內(nèi)存允許,相加多大的數(shù)都可以。

    /**

     * 超大整數(shù)相加:

     * 題目要求:如果系統(tǒng)要使用超大整數(shù)(超過(guò)long的范圍),請(qǐng)你設(shè)計(jì)一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)這種

     * 超大型數(shù)字以及設(shè)計(jì)一種算法來(lái)實(shí)現(xiàn)超大整數(shù)的加法運(yùn)算

     * @author Administrator

     *

     */

    public class VeryBigNumAdd {

     

        /**

         * @param args

         */

        public static void main(String[] args) {

           // TODO Auto-generated method stub

           /*

           String a="1223232";

           for(int i=a.length()-1;i>=0;i--)

           {

               System.out.print(a.charAt(i));

           }

           */

           VeryBigNumAdd vbn=new VeryBigNumAdd();

           String a="123453243455535634535252345234677576252241234123523453664563634";

           String b="123453243455535634535252345234677576252241234123523453664563634";

           String result=vbn.doAdd(a,b);

           System.out.println("result:"+result);

        }

        /**

         *

         * @param a 加數(shù)字符串1

         * @param b 加數(shù)字符串2

         * @return 結(jié)果字符串

         * 分析:

         * 1、取得兩個(gè)字符串的長(zhǎng)度

         * 2、把兩個(gè)的長(zhǎng)度做比較,并得出較長(zhǎng)的長(zhǎng)度,及較短的長(zhǎng)度

         * 3、把長(zhǎng)度較短的加數(shù)字符串,在左面補(bǔ)0,使之與較長(zhǎng)的字符串一樣長(zhǎng)

         * 4、從最高位,一個(gè)個(gè)數(shù)的取出來(lái)相加,當(dāng)然首先得轉(zhuǎn)換為整型

         * 5、設(shè)置進(jìn)位,如果兩個(gè)數(shù)相加及加上進(jìn)位大于等于10,并且這不是最左邊一個(gè)字符相加,相加結(jié)果等于

         *    (取出1+取出2+進(jìn)位)-10,并把進(jìn)位設(shè)為1;如果沒(méi)有大于10,就把進(jìn)位設(shè)為0,如些循環(huán),把

         *    相加的結(jié)果以字符串的形式結(jié)合起來(lái),就得到最后的結(jié)果

         */

        String doAdd(String a,String b)

        {

           String str="";

           int lenA=a.length();

           int lenB=b.length();

           int maxLen=(lenA>lenB) ? lenA : lenB;

           int minLen=(lenA<lenB) ? lenA : lenB;

           String strTmp="";

           for(int i=maxLen-minLen;i>0;i--)

           {

               strTmp+="0";

           }

           //把長(zhǎng)度調(diào)整到相同

           if(maxLen==lenA)

           {

               b=strTmp+b;

           }else

               a=strTmp+a;

           int JW=0;//進(jìn)位

           for(int i=maxLen-1;i>=0;i--)

           {        

               int tempA=Integer.parseInt(String.valueOf(a.charAt(i)));

               int tempB=Integer.parseInt(String.valueOf(b.charAt(i)));

               int temp;

               if(tempA+tempB+JW>=10 && i!=0)

               {

                  temp=tempA+tempB+JW-10;

                  JW=1;

               }

               else

               {

                  temp=tempA+tempB+JW;

                  JW=0;

               }        

               str=String.valueOf(temp)+str;        

           }

           return str;

        }

     

    }

     

    原帖地址: http://blog.csdn.net/fenglibing/archive/2007/08/23/1756773.aspx

        
        其實(shí)java 本身也提供了api ,java.math.BigInteger;import java.math.BigDecimal; 也可以實(shí)現(xiàn)。

    code :

    package com.kangdy.test;

    import java.math.BigInteger;
    import java.math.BigDecimal;

    public class NumberTest {
     public static void main(String args[]){
      BigInteger b1= new BigInteger("2222222222222222222222222");
      BigInteger b2= new BigInteger("8888888888888888888888888");
      BigDecimal b3 = new BigDecimal("66666666666666666666666666");
      BigDecimal b4 = new BigDecimal("9999999999999999999999999999");
      System.out.println(b1.add(b2).toString());
      System.out.println(b3.add(b4).toString());
     }
    }

    這里只是給出簡(jiǎn)單的例子。



    posted @ 2010-12-10 14:06 AK47 閱讀(926) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼)java回調(diào)函數(shù)

    原帖地址: http://ayzw001.blog.163.com/blog/static/1134114222009420112538726/

    引用:

           所謂回調(diào),就是客戶(hù)程序C調(diào)用服務(wù)程序S中的某個(gè)方法a,然后S又在某個(gè)時(shí)候反過(guò)來(lái)調(diào)用C中的某個(gè)方法b,對(duì)于C來(lái)說(shuō),這個(gè)b便叫做回調(diào)函數(shù)。

    一般說(shuō)來(lái),C不會(huì)自己調(diào)用b,C提供b的目的就是讓S來(lái)調(diào)用它,而且是C不得不提供。由于S并不知道C提供的b叫甚名誰(shuí),所以S會(huì)約定b的接口規(guī)范(函數(shù)原型),然后由C提前通過(guò)S的一個(gè)函數(shù)r告訴S自己將要使用b函數(shù),這個(gè)過(guò)程稱(chēng)為回調(diào)函數(shù)的注冊(cè),r稱(chēng)為注冊(cè)函數(shù)。

    下面舉個(gè)通俗的例子:

    某天,我打電話向你請(qǐng)教問(wèn)題,當(dāng)然是個(gè)難題,:),你一時(shí)想不出解決方法,我又不能拿著電話在那里傻等,于是我們約定:等你想出辦法后打手機(jī)通知我,這樣,我就掛掉電話辦其它事情去了。過(guò)了XX分鐘,我的手機(jī)響了,你興高采烈的說(shuō)問(wèn)題已經(jīng)搞定,應(yīng)該如此這般處理。故事到此結(jié)束。

    這個(gè)例子說(shuō)明了“異步+回調(diào)”的編程模式。其中,你后來(lái)打手機(jī)告訴我結(jié)果便是一個(gè)“回調(diào)”過(guò)程;我的手機(jī)號(hào)碼必須在以前告訴你,這便是注冊(cè)回調(diào)函數(shù);我的手機(jī)號(hào)碼應(yīng)該有效并且手機(jī)能夠接收到你的呼叫,這是回調(diào)函數(shù)必須符合接口規(guī)范。

     

    如果你還不太清楚看看這段描述合和代碼:

    聲明一個(gè)接口,另外一個(gè)類(lèi)有方法里面有個(gè)參數(shù)以是這個(gè)接口類(lèi)型的,而后在另外類(lèi)中實(shí)現(xiàn)這個(gè)接口(java中多用的是匿名內(nèi)部類(lèi)),而且以這個(gè)匿名的類(lèi)生成的對(duì)象為參數(shù)傳到上面提到類(lèi)中,而后實(shí)現(xiàn)回調(diào).......這種用法可以參考java里面常用到的數(shù)據(jù)庫(kù)操作所用到的幾個(gè)接口.....

    //聲明一個(gè)接口
    public interface ICallBack {
        void postExec();
    }

     

    //另外一個(gè)類(lèi)有方法里面有個(gè)參數(shù)以是這個(gè)接口類(lèi)型的
    public class FooBar {
        private ICallBack callBack;
        public void setCallBack(ICallBack callBack) {
            this.callBack = callBack;
        }
        public void doSth() {
            callBack.postExec();
        }
    }
    ---------------------------------------
    回調(diào)的實(shí)現(xiàn)
    public class Test {
        public static void main(String[] args) {
            FooBar foo = new FooBar();
            foo.setCallBack(new ICallBack() {
                public void postExec() {
                    System.out.println("method executed.");
                }
            });
            foo.doSth();//調(diào)用函數(shù)
        }
    }

    posted @ 2010-12-10 11:22 AK47 閱讀(626) | 評(píng)論 (0)編輯 收藏

    (轉(zhuǎn)貼) 真正理解面向接口編程

    面向?qū)ο笤O(shè)計(jì)里有一點(diǎn)大家已基本形成共識(shí),就是面向接口編程,我想大多數(shù)人對(duì)這個(gè)是沒(méi)有什么覺(jué)得需要懷疑的。

    問(wèn)題是在實(shí)際的項(xiàng)目開(kāi)發(fā)中我們是怎么體現(xiàn)的呢? 難道就是每一個(gè)實(shí)現(xiàn)都提供一個(gè)接口就了事了?反過(guò)來(lái)說(shuō),你有時(shí)候有沒(méi)有覺(jué)得接口是多余的事? 又或者,你僅僅是覺(jué)得現(xiàn)在類(lèi)似spring這樣的框架已習(xí)慣用接口這種方式而心存當(dāng)然。

    設(shè)計(jì)模式解析里提到了面向?qū)ο笤O(shè)計(jì)考慮的幾個(gè)視角,一個(gè)是概念層,一個(gè)是規(guī)約層,一個(gè)是實(shí)現(xiàn)層。我如果沒(méi)有猜錯(cuò)的話,實(shí)際上我們大多數(shù)人的眼睛一直是盯著實(shí)現(xiàn)層的,而這正是面向?qū)ο笤O(shè)計(jì)所極力避免的,即你不要在一開(kāi)始就關(guān)注這些細(xì)節(jié),你要關(guān)注的是規(guī)約(接口).

    對(duì)于實(shí)際項(xiàng)目開(kāi)發(fā)來(lái)說(shuō),如果我們把實(shí)現(xiàn)的過(guò)程分為多個(gè)階段的話我們不妨這么劃分,第一階段,根據(jù)client端的需要去設(shè)計(jì)我們的規(guī)約(interface),在這個(gè)階段任何實(shí)現(xiàn)都沒(méi)有,所有的任務(wù)就是定義接口所需要的職責(zé),以及所需要的一些po,vo;第二階段,實(shí)現(xiàn)前面定義的規(guī)約。而以前我是怎么做的呢? 我是交叉作的,即假模假樣的定義一個(gè)接口(其實(shí)我心里在想這個(gè)東西有屁用),然后定義了一個(gè)方法,然后就立即去實(shí)現(xiàn)這個(gè)方法,再然后我又定義一個(gè)方法,繼續(xù)去實(shí)現(xiàn),我現(xiàn)在終于想通了,這樣好累,效率很低,最重要的是,這不屬于真正的設(shè)計(jì)。
    現(xiàn)在我是怎么做的呢?比如一個(gè)list.jsp里需要查詢(xún),列表,然后看明細(xì)信息,然后增加信息,我會(huì)第一步在接口里定義完(這個(gè)過(guò)程會(huì)有整體設(shè)計(jì)的意識(shí)),毫不關(guān)心底層實(shí)現(xiàn)(數(shù)據(jù)庫(kù)、事務(wù)),我的目標(biāo)就是"我想要這個(gè)功能,我想要那個(gè)功能",至于那個(gè)功能怎么實(shí)現(xiàn)在第一階段我認(rèn)為那不是我的事情(盡管這個(gè)事情最終還是由我來(lái)做) .大家看這個(gè)過(guò)程和前面的過(guò)程有什么本質(zhì)的不同呢? 就是分層的概念更加明顯,你的工作更有層次,每次都有先設(shè)計(jì)再實(shí)現(xiàn)的步驟,而前面那個(gè)過(guò)程很容易就讓你不知不覺(jué)地陷入純實(shí)現(xiàn)的陷阱中。

    一點(diǎn)感想,歡迎大家拍磚。

    原帖地址: http://www.tkk7.com/alex/archive/2007/03/12/103185.html

    posted @ 2010-11-05 14:09 AK47 閱讀(317) | 評(píng)論 (0)編輯 收藏

    數(shù)字金額的中文大小寫(xiě)轉(zhuǎn)化

    曾經(jīng)去過(guò)一家公司面試。筆試題的最后一題是一個(gè)數(shù)字金額大小寫(xiě)轉(zhuǎn)化的問(wèn)題。
    當(dāng)時(shí)沒(méi)想那么多,僅僅想到應(yīng)該把數(shù)拆開(kāi)然后添加單位的一個(gè)大致的設(shè)計(jì)思路。
    而那個(gè)面試官一個(gè)勁兒的問(wèn)我用啥算法。那個(gè)題最后也沒(méi)答上,回來(lái)后比較郁悶,
    在網(wǎng)上搜了一下。這個(gè)答案還真不少。不過(guò)覺(jué)得有一種設(shè)計(jì)還比較靠譜。
    大概是這樣:
     * 先將整數(shù)與小數(shù)部分分開(kāi),計(jì)算小數(shù)部分,角分并保存
     * 整數(shù)部分長(zhǎng)度不足12位,前面加0補(bǔ)足。
     * 將整數(shù)部分分割3部分。高4位代表億,中間的是萬(wàn),其余分別代表千,百,十,個(gè)
     * 定一個(gè)方法拼出每一部分串。
     * 最后整數(shù)與小數(shù)部分合成。

    自己實(shí)現(xiàn)了一下,以下是代碼。
    code :

    package com.kangdy.test;
    /**
     * 數(shù)字金額轉(zhuǎn)化成大寫(xiě)
     * 先將整數(shù)與小數(shù)部分分開(kāi),計(jì)算小數(shù)部分,角分并保存
     * 整數(shù)部分長(zhǎng)度不足12位,前面加0補(bǔ)足。
     * 將整數(shù)部分分割3部分。高4位代表億,中間的是萬(wàn),其余分別代表千,百,十,個(gè)
     * 定一個(gè)方法拼出每一部分串。
     * 最后整數(shù)與小數(shù)部分合成。
     * @author dkang
     *
     */
    public class NumberToString {

     String numberStr;

     public static final String unit[] = { "", "十", "百", "千", "萬(wàn)", "億" };

     public static final String unit2[] = { "元", "角", "分" };

     public static final String numStr[] = { "零", "壹", "貳", "叁", "肆", "伍", "陸",
       "柒", "捌", "玖" };

     /**
      * 字符串長(zhǎng)度不足12位用0補(bǔ)足
      *
      * @param str
      * @return
      */
     private String additionalZero(String str) {
      StringBuffer strb = new StringBuffer();
      if (str.length() < 12) {
       int size = 12 - str.length();
       for (int i = 0; i < size; i++) {
        strb.append("0");
       }
      }
      return strb.append(str).toString();
     }

     /**
      * 遞歸拆分?jǐn)?shù)字成字符串
      *
      * @param value
      * @param strBuffer
      * @return
      */
     private String decomposeNumberToString(int value, StringBuffer strBuffer) {
      int quotient = 0;
      quotient = value / 10;
      if (quotient != 0) {
       decomposeNumberToString(quotient, strBuffer);
      }
      int remaider = value % 10;
      strBuffer.append(remaider + ",");
      return strBuffer.toString().substring(0,
        strBuffer.toString().length() - 1);
     }

     /**
      * 使用循環(huán)拆分?jǐn)?shù)字成字符串
      *
      * @param value
      * @return
      */
     private String decomposeNumberToString2(int value) {
      StringBuilder strBuilder = new StringBuilder();
      int quotient = value;
      int remaider = 0;
      while (quotient != 0) {
       remaider = quotient % 10;
       strBuilder.append(remaider + ",");
       quotient = quotient / 10;
      }
      strBuilder.deleteCharAt(strBuilder.lastIndexOf(","));
      return strBuilder.reverse().toString();
     }

     /**
      * 添加單位
      *
      * @param temp
      * @return
      */
     private String addUnits(String temp) {
      StringBuffer sb = new StringBuffer();
      String str[] = temp.split(",");
      String tempStr = temp.replace(",", "");
      if (tempStr.contains("000")) {
       return sb.append(resplaceNumToStr(str[0]) + unit[3]).toString();
      } else if (tempStr.contains("00")) {
       if (tempStr.charAt(3) == '0') {
        return sb.append(resplaceNumToStr(str[0]) + unit[3]).append(
          resplaceNumToStr(str[1]) + unit[2]).toString();
       } else {
        return sb.append(resplaceNumToStr(str[0]) + unit[3]).append(
          numStr[0]).append(resplaceNumToStr(str[3])).toString();
       }
      } else {
       for (int i = 0; i < str.length; i++) {
        sb.append(resplaceNumToStr(str[i]));
        if (!str[i].equals("0")) {
         sb.append(unit[str.length - (i + 1)]);
        }
       }
      }
      return sb.toString();
     }

     /**
      * 數(shù)字替換
      *
      * @param str
      * @return
      */
     private String resplaceNumToStr(String str) {
      try {
       int num = Integer.parseInt(str);
       return numStr[num];
      } catch (Exception e) {
       e.printStackTrace();
      }
      return "";
     }

     /**
      * 把4位長(zhǎng)度的數(shù)字轉(zhuǎn)化成字符串
      *
      * @param number
      * @param i
      * @return
      */
     private String transformNumberToString(String number, int i) {
      StringBuffer strBuffer = new StringBuffer();
      StringBuilder strBuilder = new StringBuilder();
      try {
       int num = Integer.parseInt(number);
       if (num != 0) {
        String s1 = decomposeNumberToString(num, strBuffer);
        strBuilder.append(addUnits(s1));
        if (i == 1) {
         strBuilder.append(unit[5]);
        } else if (i == 2)
         strBuilder.append(unit[4]);
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
      return strBuilder.toString();
     }

     /**
      * 得到最終結(jié)果
      *
      * @param str
      * @return
      */
     public String IntegrationResultString(String str) {
      StringBuffer strBuffer = new StringBuffer();
      String numStr[] = null;
      if (str.indexOf(".") != -1) {
       numStr = str.split("\\.");
      } else {
       return strBuffer.append(createIntegerPartsResult(str)).toString();
      }
      String fractionalStr = createFractionalPartsResult(numStr[1]);
      String integerStr = createIntegerPartsResult(numStr[0]);
      return strBuffer.append(integerStr).append(fractionalStr).toString();
     }

     private String createIntegerPartsResult(String integer) {
      StringBuffer strBuffer = new StringBuffer();
      String temp = additionalZero(integer);
      String str1 = temp.substring(0, 4);
      strBuffer.append(transformNumberToString(str1, 1));
      String str2 = temp.substring(4, 8);
      strBuffer.append(transformNumberToString(str2, 2));
      String str3 = temp.substring(8, temp.length());
      strBuffer.append(transformNumberToString(str3, 3) + unit2[0]);
      return strBuffer.toString();
     }

     private String createFractionalPartsResult(String fractionalStr) {
      StringBuilder strB = new StringBuilder();
      String s1 = fractionalStr.substring(0, 1);
      String s2 = fractionalStr.substring(1, fractionalStr.length());
      if (!s1.equals("0")) {
       strB.append(resplaceNumToStr(s1) + unit2[1]);
      }
      if (!s2.equals("0")) {
       strB.append(resplaceNumToStr(s2) + unit2[2]);
      }
      return strB.toString();
     }

     public static void main(String args[]) {
      NumberToString test = new NumberToString();
      String str = "200123004054.11";
      System.out.println(test.IntegrationResultString(str));
     }
    }



    posted @ 2010-11-02 14:59 AK47 閱讀(610) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題
    共4頁(yè): 上一頁(yè) 1 2 3 4 下一頁(yè) 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿

    隨筆分類(lèi)

    隨筆檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲国产欧美一区二区三区 | 国产精品成人免费福利| **一级毛片免费完整视| 100000免费啪啪18免进| 免费观看男人免费桶女人视频| 精品国产精品久久一区免费式| 四虎永久在线精品免费影视| 亚洲伊人久久综合影院| 久久精品国产亚洲av成人| 亚洲无成人网77777| 亚洲精品无码专区| eeuss影院www天堂免费| 亚洲精品免费在线视频| 日韩免费一级毛片| 永久亚洲成a人片777777| 亚洲视频在线观看地址| 亚洲乱码国产乱码精华| 中文毛片无遮挡高清免费| 99视频在线免费| 日韩成人免费视频播放| 中文字幕亚洲图片| 亚洲成a人片毛片在线| 另类专区另类专区亚洲| 免费久久人人爽人人爽av| 免费视频专区一国产盗摄| 一本色道久久88综合亚洲精品高清| 亚洲精品成人片在线观看精品字幕| 亚洲毛片无码专区亚洲乱| 国产成人高清亚洲一区久久| 久章草在线精品视频免费观看| 无码中文字幕av免费放| 亚洲一级片内射网站在线观看| 久久久久亚洲av无码专区喷水| 亚洲AV永久无码天堂影院| 99视频免费在线观看| 97无码免费人妻超级碰碰碰碰 | 永久免费av无码网站韩国毛片| 亚洲精品麻豆av| 亚洲一线产区二线产区精华| 一日本道a高清免费播放| 男人的好免费观看在线视频|