Java && C#

          要學得東西很多,但我們的時間卻不是很多!
          數(shù)據(jù)加載中……

          2007年3月13日

          點點滴滴

               N長時間沒有來了.......
               忙中偷閑,整理點代碼。
               /** 
               *  復制單個文件 
               *  @param  oldPath  String  原文件路徑  如:c:/fqf.txt 
               *  @param  newPath  String  復制后路徑  如:f:/fqf.txt 
               *  @return  boolean 
               */ 
             public  void  copyFile(String  oldPath,  String  newPath) 
             { 
                 try  { 
                     int  bytesum  =  0; 
                     int  byteread  =  0; 
                     File  oldfile  =  new  File(oldPath); 
                     if  (oldfile.exists())  {  //文件存在時 
                         InputStream  inStream  =  new  FileInputStream(oldPath);  //讀入原文件 
                         FileOutputStream  fs  =  new  FileOutputStream(newPath); 
                         byte[]  buffer  =  new  byte[1444]; 
                         int  length; 
                         while  (  (byteread  =  inStream.read(buffer))  !=  -1)  { 
                             bytesum  +=  byteread;  //字節(jié)數(shù)  文件大小 
                             System.out.println(bytesum); 
                             fs.write(buffer,  0,  byteread); 
                         } 
                         inStream.close(); 
                     } 
                 } 
                 catch  (Exception  e)  { 
                     System.out.println("復制單個文件操作出錯"); 
                     e.printStackTrace();  
                 }  
             }  

          //保存文件的方法
          public String Savefiles(FormFile file,String path)
           {  
            String fileName= file.getFileName();
            String contentType = file.getContentType();
            String size = (file.getFileSize() + " bytes");
            try
            {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             InputStream stream = file.getInputStream();
             OutputStream bos = new FileOutputStream(path+fileName);
             int bytesRead = 0;
             byte[] buffer = new byte[8192];
             while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
              bos.write(buffer, 0, bytesRead);
             }
             bos.close();      
             stream.close();  
            }
            catch (IOException e) {
             return e.getMessage();
            }
            return "1";
           }

          //生成15位的字符串
          public String GenTradeId()
           {
            String tradeId = "";
            RandomStrg.setCharset("a-zA-Z0-9");  
            RandomStrg.setLength("15");  
            try
            {
             RandomStrg.generateRandomObject();
             tradeId=RandomStrg.getRandom();   
            }
            catch (Exception e)
            {    
            }
            return tradeId;  
           }

          /**
            * 刪除字符串中的空格,至多只保留一個空格
            * 
            * @String txt:輸入需要處理的字符串
            * @return String :返回處理后的字符串
            * 
            */
           public String deleteWhitespace(String txt){
            if((txt!=null)&&(txt.trim().length()>1)){
             
            }
            else{
             return "";
            }
            
            txt = txt.replaceAll("\n"," ").replaceAll("\t"," ");
            String temp="";
            try{
             int flag =0,num=0;
             char c = 'x';
             StringBuffer sb = new StringBuffer("");
             for(int x=0;x<txt.length();x++){
              c = txt.charAt(x);
              if((c==' ')&&(flag==0)){
               sb.append(c);
               flag =1;
              }
              else if((c!=' ')){
               sb.append(c);
               flag =0;
              }
             }
             temp = sb.toString().trim();
            }
            catch(Exception e){
             ;
            }
            return temp;
           }

          posted @ 2007-08-08 11:03 Bill111 閱讀(1536) | 評論 (0)編輯 收藏
          JavaScript Example

               摘要: 1.文本框焦點問題onBlur:當失去輸入焦點后產生該事件onFocus:當輸入獲得焦點后,產生該文件Onchange:當文字值改變時,產生該事件Onselect:當文字加亮后,產生該文件 <input type="text" value="郭強" onfocus="if(value=='郭強') {value=''}" onblur="if (value=='')...  閱讀全文

          posted @ 2007-03-27 17:18 Bill111 閱讀(2254) | 評論 (0)編輯 收藏
          SQL執(zhí)行效率

          SQL語句中,IN、EXISTS、NOT IN、NOT EXISTS的效率較低,尤其是后兩種語句,當數(shù)據(jù)量較大時,更常給人一種死機般的感覺。本文提供一種使用連接的方法代替以上的四種語句,可大副提高SQL語句的運行效率。以NOT IN為例,當數(shù)據(jù)量達到一萬時,效率可提高20倍,數(shù)據(jù)量越大,效率提高的幅度也就越大。

          本文所舉的例子在Oracle 7.0下運行通過,但本文所推薦的方法在各種大型數(shù)據(jù)庫上皆適用。
          為了能夠更好的說明問題,我們采用示例的方式來說明問題。下面,我們將創(chuàng)建一些數(shù)據(jù)庫表和數(shù)據(jù),用于在舉例時使用。

          下面的語句將創(chuàng)建我們示例中將使用的表,并分別在表1(TAB1)中存入10000條數(shù)據(jù),表2(TAB2)中存入5000條數(shù)據(jù)。

          SQL語句如下:

          CREATE TABLE TAB1
          (
          COL1 VARCHAR(20) NOT NULL,
          COL2 INTEGER,
          PRIMARY KEY(COL1)
          );
          CREATE TABLE TAB2
          (
          COL1 VARCHAR(20) NOT NULL,
          PRIMARY KEY(COL1)
          );
          CREATE TABLE TAB3
          (
          COL1 VARCHAR(20) NOT NULL,
          PRIMARY KEY(COL1)
          );
          CREATE OR REPLACE TRIGGER T_TAB3 BEFORE INSERT ON TAB3 FOR EACH ROW
          DECLARE
          NUM1 NUMBER;
          BEGIN
          NUM1:=1;
          LOOP
          EXIT WHEN NUM1>10000;
          INSERT INTO TAB1 VALUES (NUM1,NUM1);
          IF NUM1<=5000 THEN INSERT INTO TAB2 VALUES (NUM1);
          END IF;
          NUM1:=NUM1+1;
          END LOOP;
          END;
          INSERT INTO TAB3 VALUES('1');

          下面,我們將舉2個例子來具體說明使用連接替換IN、NOT IN、EXISTS、NOT EXISTS的方法。

           讀取表1中第2列(COL2)數(shù)據(jù)的總和,且其第1列數(shù)據(jù)存在于表2的第1列中。

          1. 使用IN的SQL語句:

          SELECT SUM(COL2) FROM TAB1 WHERE COL1 IN(SELECT COL1 FROM TAB2)

          2. 使用EXISTS的SQL語句:

          SELECT SUM(COL2) FROM TAB1 WHERE EXISTS(SELECT * FROM TAB2 WHERE TAB1.COL1=TAB2.COL1)

          3. 使用連接的SQL語句:

          SELECT SUM(A.COL2) FROM TAB1 A,TAB2 B

          WHERE A.COL1=B.COL1

           讀取表1中第2列(COL2)數(shù)據(jù)的總和,且其第1列數(shù)據(jù)不存在于表2的第1列中。


          1. 使用NOT IN的SQL語句:

          SELECT SUM(COL2) FROM TAB1 WHERE COL1 NOT IN(SELECT COL1 FROM TAB2)

          2. 使用NOT EXISTS的SQL語句:

          SELECT SUM(COL2) FROM TAB1 WHERE NOT EXISTS(SELECT * FROM TAB2 WHERE
          TAB1.COL1=TAB2.COL1)

          3. 使用外連接的SQL語句:

          SELECT SUM(A.COL2) FROM TAB1 A,TAB2 B WHERE A.COL1=B.COL1(+) AND B.COL1 IS NULL

          下面介紹IN、NOT IN、EXIST、NOT EXIST在DELETE和UPDATE語句中的效率提高方法。

          下面所舉的例子在Microsoft SQL Server 7.0下運行通過,但所推薦的方法在各種大型數(shù)據(jù)庫上皆適用。下面,我們將創(chuàng)建一些數(shù)據(jù)庫表和數(shù)據(jù),用于舉例說明。我們將分別在表A(TA)中存入 10000條數(shù)據(jù),表B(TB)中存入5000條數(shù)據(jù)。

          SQL語句如下:

          CREATE TABLE TA
          (
          CA INT
          )
          CREATE TABLE TB
          (
          CA INT
          )
          CREATE TABLE TC
          (
          CA INT
          )
          CREATE TRIGGER TRA ON TC
          FOR INSERT
          AS
          DECLARE @MINT INT
          BEGIN
          SELECT @MINT=1
          WHILE (@MINT<=5000)
          BEGIN
          INSERT INTO TA VALUES(@MINT)
          INSERT INTO TB VALUES(@MINT)
          SELECT @MINT=@MINT+1
          END
          WHILE (@MINT<=10000)
          BEGIN
          INSERT INTO TA VALUES(@MINT)
          SELECT @MINT=@MINT+1
          END
          END
          GO
          INSERT INTO TC VALUES(1)
          GO

           刪除表A中表A和表B相同的數(shù)據(jù)

          1. 用IN的SQL語句:
          DELETE FROM TA WHERE TA.CA IN (SELECT CA FROM TB)

          2. 用EXISTS的SQL語句:
          DELETE FROM TA WHERE EXISTS (SELECT * FROM TB WHERE TB.CA=TA.CA)

          3. 使用連接的SQL語句:
          DELETE TA FROM TA,TB WHERE TA.CA=TB.CA

           刪除表A中表A存在但表B中不存在的數(shù)據(jù)

          1. 使用IN的SQL語句:
          DELETE FROM TA WHERE TA.CA NOT IN (SELECT CA FROM TB)

          2. 使用EXISTS的SQL語句:
          DELETE FROM TA WHERE NOT EXISTS (SELECT CA FROM TB WHERE TB.CA=TA.CA)

          3. 使用連接的SQL語句:
          DELETE TA FROM TA LEFT OUTER JOIN TB ON TA.CA=TB.CA WHERE TB.CA IS NULL


           更新表A中表A和表B相同的數(shù)據(jù)
          1. 使用IN的SQL語句:
          UPDATE TA SET CA=CA+10000 WHERE CA IN (SELECT CA FROM TB)

          2. 使用EXISTS的SQL語句:
          UPDATE TA SET CA=CA+10000 WHERE EXISTS (SELECT CA FROM TB WHERE TB.CA=TA.CA)

          3. 使用連接的SQL語句:
          UPDATE TA SET TA.CA=TA.CA+10000 FROM TA,TB WHERE TA.CA=TB.CA


           更新表A中表A存在但表B中不存在的數(shù)據(jù)

          1. 使用IN的SQL語句:
          UPDATE TA SET CA=CA+10000 WHERE CA NOT IN (SELECT CA FROM TB)

          2. 使用EXISTS的SQL語句:
          UPDATE TA SET CA=CA+10000 WHERE NOT EXISTS (SELECT CA FROM TB WHERE TB.CA=TA.CA)

          3. 使用連接的SQL語句:
          UPDATE TA SET TA.CA=TA.CA+10000 FROM TA LEFT OUTER JOIN TB ON TA.CA=TB.CA WHERE TB.CA IS NULL

          posted @ 2007-03-23 13:50 Bill111 閱讀(3624) | 評論 (2)編輯 收藏
          java基礎知識回顧

          問題一:我聲明了什么!

          String s = "Hello world!";

          許多人都做過這樣的事情,但是,我們到底聲明了什么?回答通常是:一個String,內容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準確的回答,一半的人大概會回答錯誤。
          這個語句聲明的是一個指向對象的引用,名為“s”,可以指向類型為String的任何對象,目前指向"Hello world!"這個String類型的對象。這就是真正發(fā)生的事情。我們并沒有聲明一個String對象,我們只是聲明了一個只能指向String對象的引用變量。所以,如果在剛才那句語句后面,如果再運行一句:

          String string = s;

          我們是聲明了另外一個只能指向String對象的引用,名為string,并沒有第二個對象產生,string還是指向原來那個對象,也就是,和s指向同一個對象。

          問題二:"=="和equals方法究竟有什么區(qū)別?

          ==操作符專門用來比較變量的值是否相等。比較好理解的一點是:
          int a=10;
          int b=10;
          則a==b將是true。
          但不好理解的地方是:
          String a=new String("foo");
          String b=new String("foo");
          則a==b將返回false。

          根據(jù)前一帖說過,對象變量其實是一個引用,它們的值是指向對象所在的內存地址,而不是對象本身。a和b都使用了new操作符,意味著將在內存中產生兩個內容為"foo"的字符串,既然是“兩個”,它們自然位于不同的內存地址。a和b的值其實是兩個不同的內存地址的值,所以使用"=="操作符,結果會是 false。誠然,a和b所指的對象,它們的內容都是"foo",應該是“相等”,但是==操作符并不涉及到對象內容的比較。
          對象內容的比較,正是equals方法做的事。

          看一下Object對象的equals方法是如何實現(xiàn)的:
          boolean equals(Object o){

          return this==o;

          }
          Object 對象默認使用了==操作符。所以如果你自創(chuàng)的類沒有覆蓋equals方法,那你的類使用equals和使用==會得到同樣的結果。同樣也可以看出, Object的equals方法沒有達到equals方法應該達到的目標:比較兩個對象內容是否相等。因為答案應該由類的創(chuàng)建者決定,所以Object把這個任務留給了類的創(chuàng)建者。

          看一下一個極端的類:
          Class Monster{
          private String content;
          ...
          boolean equals(Object another){ return true;}

          }
          我覆蓋了equals方法。這個實現(xiàn)會導致無論Monster實例內容如何,它們之間的比較永遠返回true。

          所以當你是用equals方法判斷對象的內容是否相等,請不要想當然。因為可能你認為相等,而這個類的作者不這樣認為,而類的equals方法的實現(xiàn)是由他掌握的。如果你需要使用equals方法,或者使用任何基于散列碼的集合(HashSet,HashMap,HashTable),請察看一下java doc以確認這個類的equals邏輯是如何實現(xiàn)的。

          問題三:String到底變了沒有?

          沒有。因為String被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。請看下列代碼:

          String s = "Hello";
          s = s + " world!";

          s 所指向的對象是否改變了呢?從本系列第一篇的結論很容易導出這個結論。我們來看看發(fā)生了什么事情。在這段代碼中,s原先指向一個String對象,內容是 "Hello",然后我們對s進行了+操作,那么s所指向的那個對象是否發(fā)生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個 String對象,內容為"Hello world!",原來那個對象還存在于內存之中,只是s這個引用變量不再指向它了。
          通過上面的說明,我們很容易導出另一個結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那么使用String來代表字符串的話會引起很大的內存開銷。因為 String對象建立之后不能再改變,所以對于每一個不同的字符串,都需要一個String對象來表示。這時,應該考慮使用StringBuffer類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。并且,這兩種類的對象轉換十分容易。
          同時,我們還可以知道,如果要使用內容相同的字符串,不必每次都new一個String。例如我們要在構造器中對一個名叫s的String引用變量進行初始化,把它設置為初始值,應當這樣做:
          public class Demo {
          private String s;
          ...
          public Demo {
          s = "Initial Value";
          }
          ...
          }
          而非
          s = new String("Initial Value");
          后者每次都會調用構造器,生成新對象,性能低下且內存開銷大,并且沒有意義,因為String對象不可改變,所以對于內容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調用上面的構造器創(chuàng)建多個對象,他們的String類型屬性s都指向同一個對象。
          上面的結論還基于這樣一個事實:對于字符串常量,如果內容相同,Java認為它們代表同一個String對象。而用關鍵字new調用構造器,總是會創(chuàng)建一個新的對象,無論內容是否相同。
          至于為什么要把String類設計成不可變類,是它的用途決定的。其實不只String,很多Java標準類庫中的類都是不可變的。在開發(fā)一個系統(tǒng)的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現(xiàn)。不可變類有一些優(yōu)點,比如因為它的對象是只讀的,所以多線程并發(fā)訪問也不會有任何問題。當然也有一些缺點,比如每個不同的狀態(tài)都要一個對象來代表,可能會造成性能上的問題。所以Java標準類庫還提供了一個可變版本,即 StringBuffer。

          問題四:final關鍵字到底修飾了什么?

          final使得被修飾的變量"不變",但是由于對象型變量的本質是“引用”,使得“不變”也有了兩種含義:引用本身的不變,和引用指向的對象不變。

          引用本身的不變:
          final StringBuffer a=new StringBuffer("immutable");
          final StringBuffer b=new StringBuffer("not immutable");
          a=b;//編譯期錯誤

          引用指向的對象不變:
          final StringBuffer a=new StringBuffer("immutable");
          a.append(" broken!"); //編譯通過

          可見,final只對引用的“值”(也即它所指向的那個對象的內存地址)有效,它迫使引用只能指向初始指向的那個對象,改變它的指向會導致編譯期錯誤。至于它所指向的對象的變化,final是不負責的。這很類似==操作符:==操作符只負責引用的“值”相等,至于這個地址所指向的對象內容是否相等,==操作符是不管的。

          理解final問題有很重要的含義。許多程序漏洞都基于此----final只能保證引用永遠指向固定對象,不能保證那個對象的狀態(tài)不變。在多線程的操作中,一個對象會被多個線程共享或修改,一個線程對對象無意識的修改可能會導致另一個使用此對象的線程崩潰。一個錯誤的解決方法就是在此對象新建的時候把它聲明為final,意圖使得它“永遠不變”。其實那是徒勞的。

          問題五:到底要怎么樣初始化!

          本問題討論變量的初始化,所以先來看一下Java中有哪些種類的變量。
          1. 類的屬性,或者叫值域
          2. 方法里的局部變量
          3. 方法的參數(shù)

          對于第一種變量,Java虛擬機會自動進行初始化。如果給出了初始值,則初始化為該初始值。如果沒有給出,則把它初始化為該類型變量的默認初始值。

          int類型變量默認初始值為0
          float類型變量默認初始值為0.0f
          double類型變量默認初始值為0.0
          boolean類型變量默認初始值為false
          char類型變量默認初始值為0(ASCII碼)
          long類型變量默認初始值為0
          所有對象引用類型變量默認初始值為null,即不指向任何對象。注意數(shù)組本身也是對象,所以沒有初始化的數(shù)組引用在自動初始化后其值也是null。

          對于兩種不同的類屬性,static屬性與instance屬性,初始化的時機是不同的。instance屬性在創(chuàng)建實例的時候初始化,static屬性在類加載,也就是第一次用到這個類的時候初始化,對于后來的實例的創(chuàng)建,不再次進行初始化。這個問題會在以后的系列中進行詳細討論。

          對于第二種變量,必須明確地進行初始化。如果再沒有初始化之前就試圖使用它,編譯器會抗議。如果初始化的語句在try塊中或if塊中,也必須要讓它在第一次使用前一定能夠得到賦值。也就是說,把初始化語句放在只有if塊的條件判斷語句中編譯器也會抗議,因為執(zhí)行的時候可能不符合if后面的判斷條件,如此一來初始化語句就不會被執(zhí)行了,這就違反了局部變量使用前必須初始化的規(guī)定。但如果在else塊中也有初始化語句,就可以通過編譯,因為無論如何,總有至少一條初始化語句會被執(zhí)行,不會發(fā)生使用前未被初始化的事情。對于try-catch也是一樣,如果只有在try塊里才有初始化語句,編譯部通過。如果在 catch或finally里也有,則可以通過編譯。總之,要保證局部變量在使用之前一定被初始化了。所以,一個好的做法是在聲明他們的時候就初始化他們,如果不知道要出事化成什么值好,就用上面的默認值吧!

          其實第三種變量和第二種本質上是一樣的,都是方法中的局部變量。只不過作為參數(shù),肯定是被初始化過的,傳入的值就是初始值,所以不需要初始化。

          問題六:instanceof是什么東東?

          instanceof是Java的一個二元操作符,和==,>,<是同一類東東。由于它是由字母組成的,所以也是Java的保留關鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回boolean類型的數(shù)據(jù)。舉個例子:

          String s = "I AM an Object!";
          boolean isObject = s instanceof Object;

          我們聲明了一個String對象引用,指向一個String對象,然后用instancof來測試它所指向的對象是否是Object類的一個實例,顯然,這是真的,所以返回true,也就是isObject的值為True。
          instanceof有一些用處。比如我們寫了一個處理賬單的系統(tǒng),其中有這樣三個類:

          public class Bill {//省略細節(jié)}
          public class PhoneBill extends Bill {//省略細節(jié)}
          public class GasBill extends Bill {//省略細節(jié)}

          在處理程序里有一個方法,接受一個Bill類型的對象,計算金額。假設兩種賬單計算方法不同,而傳入的Bill對象可能是兩種中的任何一種,所以要用instanceof來判斷:

          public double calculate(Bill bill) {
          if (bill instanceof PhoneBill) {
          //計算電話賬單
          }
          if (bill instanceof GasBill) {
          //計算燃氣賬單
          }
          ...
          }
          這樣就可以用一個方法處理兩種子類。

          然而,這種做法通常被認為是沒有好好利用面向對象中的多態(tài)性。其實上面的功能要求用方法重載完全可以實現(xiàn),這是面向對象變成應有的做法,避免回到結構化編程模式。只要提供兩個名字和返回值都相同,接受參數(shù)類型不同的方法就可以了:

          public double calculate(PhoneBill bill) {
          //計算電話賬單
          }

          public double calculate(GasBill bill) {
          //計算燃氣賬單
          }

          所以,使用instanceof在絕大多數(shù)情況下并不是推薦的做法,應當好好利用多態(tài)。

          posted @ 2007-03-16 15:19 Bill111 閱讀(256) | 評論 (0)編輯 收藏
          何為J2ee?

          J2ee(Java 2 Enterprise Edition)是建立在Java 2平臺上的企業(yè)級應用的解決方案。J2EE技術的基礎便是Java 2平臺,不但有J2SE平臺的所有功能,同時還提供了對EJBServlet,JSP,XML等技術的全面支持,其最終目標是成為一個支持企業(yè)級應用開發(fā)的體系結構,簡化企業(yè)解決方案的開發(fā),部署和管理等復雜問題。事實上,J2EE已經成為企業(yè)級開發(fā)的工業(yè)標準和首選平臺。

            J2EE并非一個產品,而是一系列的標準。市場上可以看到很多實現(xiàn)了J2EE的產品,如BEA WebLogic,IBM WebSphere以及開源JBoss等等。

          ????? J2EE,是sun公司提出的一個標準,符合這個標準的產品叫"實現(xiàn)";其中你下載的sun公司的j2ee開發(fā)包中就有一個這樣的"實現(xiàn)",而 jboss,weblogic,websphere都是j2ee標準的一個"實現(xiàn)"。由于jboss,weblogic,websphere自身帶有 j2ee的api,所以可以不使用sun的j2ee實現(xiàn)。

          一. J2EE的概念

          ????? 目前,Java 2平臺有3個版本,它們是適用于小型設備和智能卡的Java 2平臺Micro版(Java 2 Platform Micro Edition,J2ME)、適用于桌面系統(tǒng)的Java 2平臺標準版(Java 2 Platform Standard Edition,J2SE)、適用于創(chuàng)建服務器應用程序和服務的Java2平臺企業(yè)版(Java 2 Platform Enterprise Edition,J2EE)。

          ????? J2EE是一種利用Java 2平臺來簡化企業(yè)解決方案的開發(fā)、部署和管理相關的復雜問題的體系結構。J2EE技術的基礎就是核心Java平臺或Java 2平臺的標準版,J2EE不僅鞏固了標準版中的許多優(yōu)點,例如"編寫一次、隨處運行"的特性、方便存取數(shù)據(jù)庫JDBC API、CORBA技術以及能夠在Internet應用中保護數(shù)據(jù)的安全模式等等,同時還提供了對 EJB(Enterprise JavaBeans)、Java Servlets API、JSP(Java Server Pages)以及XML技術的全面支持。其最終目的就是成為一個能夠使企業(yè)開發(fā)者大幅縮短投放市場時間的體系結構。

          ????? J2EE體系結構提供中間層集成框架用來滿足無需太多費用而又需要高可用性、高可靠性以及可擴展性的應用的需求。通過提供統(tǒng)一的開發(fā)平臺,J2EE降低了開發(fā)多層應用的費用和復雜性,同時提供對現(xiàn)有應用程序集成強有力支持,完全支持Enterprise JavaBeans,有良好的向導支持打包和部署應用,添加目錄支持,增強了安全機制,提高了性能。

          二. J2EE的優(yōu)勢

          ???? J2EE為搭建具有可伸縮性、靈活性、易維護性的商務系統(tǒng)提供了良好的機制:
          ????? 保留現(xiàn)存的IT資產: 由于企業(yè)必須適應新的商業(yè)需求,利用已有的企業(yè)信息系統(tǒng)方面的投資,而不是重新制定全盤方案就變得很重要。這樣,一個以漸進的(而不是激進的,全盤否定的)方式建立在已有系統(tǒng)之上的服務器端平臺機制是公司所需求的。J2EE架構可 以充分利用用戶原有的投資,如一些公司使用的BEA Tuxedo、IBM CICS, IBM Encina,、Inprise VisiBroker 以及Netscape Application Server。這之所以成為可能是因為J2EE擁有廣泛的業(yè)界支持和一些重要的'企業(yè)計算'領域供應商的參與。每一個供應商都對現(xiàn)有的客戶提供了不用廢棄 已有投資,進入可移植的J2EE領域的升級途徑。由于基于J2EE平臺的產品幾乎能夠在任何操作系統(tǒng)和硬件配置上運行,現(xiàn)有的操作系統(tǒng)和硬件也能被保留使用。

          ????? 高效的開發(fā): J2EE允許公司把一些通用的、很繁瑣的服務端任務交給中間件供應商去完成。這樣開發(fā)人員可以集中精力在如何創(chuàng)建商業(yè)邏輯上,相應地縮短了開發(fā)時間。高級中間件供應商提供以下這些復雜的中間件服務:

          ????? 狀態(tài)管理服務 -- 讓開發(fā)人員寫更少的代碼,不用關心如何管理狀態(tài),這樣能夠更快地完成程序開發(fā)。
          ????? 持續(xù)性服務 -- 讓開發(fā)人員不用對數(shù)據(jù)訪問邏輯進行編碼就能編寫應用程序,能生成更輕巧,與數(shù)據(jù)庫無關的應用程序,這種應用程序更易于開發(fā)與維護。
          ????? 分布式共享數(shù)據(jù)對象CACHE服務 -- 讓開發(fā)人員編制高性能的系統(tǒng),極大提高整體部署的伸縮性。
          ????? 支持異構環(huán)境: J2EE能夠開發(fā)部署在異構環(huán)境中的可移植程序。基于J2EE的應用程序不依賴任何特定操作系統(tǒng)、中間件、硬件。因此設計合理的基于J2EE的程序只需開 發(fā)一次就可部署到各種平臺。這在典型的異構企業(yè)計算環(huán)境中是十分關鍵的。J2EE標準也允許客戶訂購與J2EE兼容的第三方的現(xiàn)成的組件,把他們部署到異構環(huán)境中,節(jié)省了由自己制訂整個方案所需的費用。
          ????? 可伸縮性: 企業(yè)必須要選擇一種服務器端平臺,這種平臺應能提供極佳的可伸縮性去滿足那些在他們系統(tǒng)上進行商業(yè)運作的大批新客戶。基于J2EE平臺的應用程序可被部署 到各種操作系統(tǒng)上。例如可被部署到高端UNIX與大型機系統(tǒng),這種系統(tǒng)單機可支持64至256個處理器。(這是NT服務器所望塵莫及的)J2EE領域的供 應商提供了更為廣泛的負載平衡策略。能消除系統(tǒng)中的瓶頸,允許多臺服務器集成部署。這種部署可達數(shù)千個處理器,實現(xiàn)可高度伸縮的系統(tǒng),滿足未來商業(yè)應用的 需要。
          ????? 穩(wěn)定的可用性: 一個服務器端平臺必須能全天候運轉以滿足公司客戶、合作伙伴的需要。因為INTERNET是全球化的、無處不在的,即使在夜間按計劃停機也可能造成嚴重損 失。若是意外停機,那會有災難性后果。J2EE部署到可靠的操作環(huán)境中,他們支持長期的可用性。一些J2EE部署在WINDOWS環(huán)境中,客戶也可選擇健 壯性能更好的操作系統(tǒng)如Sun Solaris、IBM OS/390。最健壯的操作系統(tǒng)可達到99.999%的可用性或每年只需5分鐘停機時間。這是實時性很強商業(yè)系統(tǒng)理想的選擇。

          三. J2EE 的四層模型

          ????? J2EE使用多層的分布式應用模型,應用邏輯按功能劃分為組件,各個應用組件根據(jù)他們所在的層分布在不同的機器上。事實上,sun設計J2EE的初衷正是為了解決兩層模式(client/server)的弊端,在傳統(tǒng)模式中,客戶端擔 當了過多的角色而顯得臃腫,在這種模式中,第一次部署的時候比較容易,但難于升級或改進,可伸展性也不理想,而且經常基于某種專有的協(xié)議――通常是某種數(shù) 據(jù)庫協(xié)議。它使得重用業(yè)務邏輯和界面邏輯非常困難。現(xiàn)在J2EE 的多層企業(yè)級應用模型將兩層化模型中的不同層面切分成許多層。一個多層化應用能夠為不同的每種服務提供一個獨立的層,以下是 J2EE 典型的四層結構:

          ????? 運行在客戶端機器上的客戶層組件
          ????? 運行在J2EE服務器上的Web層組件
          ????? 運行在J2EE服務器上的業(yè)務邏輯層組件
          ????? 運行在EIS服務器上的企業(yè)信息系統(tǒng)(Enterprise information system)層軟件

          ????? J2EE應用程序組件
          ????? J2EE應用程序是由組件構成的.J2EE組件是具有獨立功能的軟件單元,它們通過相關的文件組裝成J2EE應用程序,并與其他組件交互。J2EE說明書中定義了以下的J2EE組件:
          ????? 應用客戶端程序和applets是客戶層組件.
          ????? Java Servlet和JavaServer Pages(JSP)是web層組件.
          ????? Enterprise JavaBeans(EJB)是業(yè)務層組件.

          ????? 客戶層組件
          ????? J2EE應用程序可以是基于web方式的,也可以是基于傳統(tǒng)方式的.
          ????? web 層組件J2EE web層組件可以是JSP 頁面或Servlets.按照J2EE規(guī)范,靜態(tài)的HTML頁面和Applets不算是web層組件。

          ????? 正如下圖所示的客戶層那樣,web層可能包含某些 JavaBean 對象來處理用戶輸入,并把
          輸入發(fā)送給運行在業(yè)務層上的enterprise bean 來進行處理。

          ????? 業(yè)務層組件
          ????? 業(yè)務層代碼的邏輯用來滿足銀行,零售,金融等特殊商務領域的需要,由運行在業(yè)務層上的enterprise bean 進行處理. 下圖表明了一個enterprise bean 是如何從客戶端程序接收數(shù)據(jù),進行處理(如果必要的話), 并發(fā)送到EIS 層儲存的,這個過程也可以逆向進行。

          ????? 有三種企業(yè)級的bean: 會話(session) beans, 實體(entity) beans, 和 消息驅 動(message-driven) beans. 會話bean 表示與客戶端程序的臨時交互. 當客戶端程序執(zhí)行完后, 會話bean 和相關數(shù)據(jù)就會消失. 相反, 實體bean 表示數(shù)據(jù)庫的表中一行永久的記錄. 當客戶端程序中止或服務器關閉時, 就會有潛在的服務保證實體bean 的數(shù)據(jù)得以保存.消息驅動 bean 結合了會話bean 和 JMS的消息監(jiān)聽器的特性, 允許一個業(yè)務層組件異步接收JMS 消息.

          ????? 企業(yè)信息系統(tǒng)層
          ????? 企業(yè)信息系統(tǒng)層處理企業(yè)信息系統(tǒng)軟件包括企業(yè)基礎建設系統(tǒng)例如企業(yè)資源計劃 (ERP), 大型機事務處理, 數(shù)據(jù)庫系統(tǒng),和其它的遺留信息系統(tǒng). 例如,J2EE 應用組件可能為了數(shù)據(jù)庫連接需要訪問企業(yè)信息系統(tǒng)

          ????? 我們就J2EE的各種組件、服務和API,進行更加詳細的闡述,看看在開發(fā)不同類型的企業(yè)級應用時,根據(jù)各自需求和目標的不同,應當如何靈活使用并組合不同的組件和服務。

          · Servlet

          ????? Servlet是Java平臺上的CGI技術。Servlet在服務器端運行,動態(tài)地生成Web頁面。與傳統(tǒng)的CGI和許多其它類似CGI的技術相比, Java Servlet具有更高的效率并更容易使用。對于Servlet,重復的請求不會導致同一程序的多次轉載,它是依靠線程的方式來支持并發(fā)訪問的。

          · JSP

          ????? JSP(Java Server Page)是一種實現(xiàn)普通靜態(tài)HTML和動態(tài)頁面輸出混合編碼的技術。從這一點來看,非常類似Microsoft ASP、PHP等 技術。借助形式上的內容和外觀表現(xiàn)的分離,Web頁面制作的任務可以比較方便地劃分給頁面設計人員和程序員,并方便地通過JSP來合成。在運行時態(tài), JSP將會被首先轉換成Servlet,并以Servlet的形態(tài)編譯運行,因此它的效率和功能與Servlet相比沒有差別,一樣具有很高的效率。

          · EJB

          ????? EJB定義了一組可重用的組件:Enterprise Beans。開發(fā)人員可以利用這些組件,像搭積木一樣建立分布式應用。在裝配組件時,所有的Enterprise Beans都需要配置到EJB服務器(一般的Weblogic、WebSphere等J2EE應用服務器都 是EJB服務器)中。EJB服務器作為容器和低層平臺的橋梁管理著EJB容器,并向該容器提供訪問系統(tǒng)服務的能力。所有的EJB實例都運行在EJB容器 中。EJB容器提供了系統(tǒng)級的服務,控制了EJB的生命周期。EJB容器為它的開發(fā)人員代管了諸如安全性、遠程連接、生命周期管理及事務管理等技術環(huán)節(jié), 簡化了商業(yè)邏輯的開發(fā)。EJB中定義了三種Enterprise Beans:

          ◆ Session Beans

          ◆ Entity Beans

          ◆ Message-driven Beans

          · JDBC

          ????? JDBC(Java Database Connectivity,Java數(shù)據(jù)庫連接)API是一個標準SQL(Structured Query Language, 結構化查詢語言)數(shù)據(jù)庫訪問接口,它使數(shù)據(jù)庫開發(fā)人員能夠用標準Java API編寫數(shù)據(jù)庫應用程序。JDBC API主要用來連接數(shù)據(jù)庫和直接調用SQL命令執(zhí)行各種SQL語句。利用JDBC API可以執(zhí)行一般的SQL語句、動態(tài)SQL語句及帶IN和OUT參數(shù)的存儲過程。Java中的JDBC相當與Microsoft平臺中的ODBC(Open Database Connectivity)。

          · JMS

          ????? JMS(Java Message ServiceJava消息服務) 是一組Java應用接口,它提供創(chuàng)建、發(fā)送、接收、讀取消息的服務。JMS API定義了一組公共的應用程序接口和相應語法,使得Java應用能夠和各種消息中間件進行通信,這些消息中間件包括IBM MQ-Series、Microsoft MSMQ及純Java的SonicMQ。通過使用JMS API,開發(fā)人員無需掌握不同消息產品的使用方法,也可以使用統(tǒng)一的JMS API來操縱各種消息中間件。通過使用JMS,能夠最大限度地提升消息應用的可移植性。 JMS既支持點對點的消息通信,也支持發(fā)布/訂閱式的消息通信。

          · JNDI

          ????? 由于J2EE應用程序組件一般分布在不同的機器上,所以需要一種機制以便于組件客戶使用者查找和引用組件及資源。在J2EE體系中,使用JNDI (Java Naming and Directory Interface)定位各種對象,這些對象包括EJB、數(shù)據(jù)庫驅動、JDBC數(shù)據(jù)源及消息連接等。JNDI API為應用程序提供了一個統(tǒng)一的接口來完成標準的目錄操作,如通過對象屬性來查找和定位該對象。由于JNDI是獨立于目錄協(xié)議的,應用還可以使用 JNDI訪問各種特定的目錄服務,如LDAP、NDS和DNS等。

          · JTA

          ????? JTA(Java Transaction API)提供了J2EE中處理事務的標準接口,它支持事務的開始、回滾和提交。同時在一般的J2EE平臺上,總提供一個JTS(Java Transaction Service)作為標準的事務處理服務,開發(fā)人員可以使用JTA來使用JTS。

          · JCA

          ????? JCA(J2EE Connector Architecture)是J2EE體系架構的一部分,為開發(fā)人員提供了一套連接各種企業(yè)信息系統(tǒng)(EIS,包括ERP、SCM、CRM等)的體系架構,對于EIS開發(fā)商而言,它們只需要開發(fā)一套基于JCA的EIS連接適配器,開發(fā)人員就能夠在任何的J2EE應用服務器中連接并使用它。基于JCA的連接適配器的實現(xiàn),需要涉及J2EE中的事務管理、安全管理及連接管理等服務組件。

          · JMX

          ????? JMX(Java Management Extensions)的前身是JMAPI。JMX致力于解決分布式系統(tǒng)管理的問題。JMX是一種應用編程接口、 可擴展對象和方法的集合體,可以跨越各種異構操作系統(tǒng)平臺、系統(tǒng)體系結構和網絡傳輸協(xié)議,開發(fā)無縫集成的面向系統(tǒng)、網絡和服務的管理應用。JMX是一個完 整的網絡管理應用程序開發(fā)環(huán)境,它同時提供了廠商需要收集的完整的特性清單、可生成資源清單表格、圖形化的用戶接口;訪問SNMP的網絡API;主機間遠程過程調用;數(shù)據(jù)庫訪問方法等。

          · JAAS

          ????? JAAS(Java Authentication and Authorization Service)實現(xiàn)了一個Java版本的標準Pluggable Authentication Module(PAM)的框架。JAAS可用來進行用戶身份的鑒定,從而能夠可靠并安全地確定誰在執(zhí)行Java代碼。同時JAAS還能通過對用戶進行授 權,實現(xiàn)基于用戶的訪問控制。

          · JACC

          ????? JACC(Java Authorization Service Provider Contract for Containers)在J2EE應用服務器和特定的授權認證服務器之間定義了一個連接的協(xié)約,以便將各種授權認證服務器插入到J2EE產品中去。

          · JAX-RPC

          ????? 通過使用JAX-RPC(Java API for XML-based RPC),已有的Java類或Java應用都能夠被重新包裝,并以Web Services的形式發(fā)布。JAX-RPC提供了將RPC參數(shù)(in/out)編碼和解碼的API,使開發(fā)人員可以方便地使用SOAP消息來完成RPC 調用。同樣,對于那些使用EJB(Enterprise JavaBeans)的商業(yè)應用而言,同樣可以使用JAX-RPC來包裝成Web服務,而這個Web Servoce的WSDL界面是與原先的EJB的方法是對應一致的。JAX-RPC為用戶包裝了Web服務的部署和實現(xiàn),對Web服務的開發(fā)人員而言, SOAP/WSDL變得透明,這有利于加速Web服務的開發(fā)周期。

          · JAXR

          ????? JAXR(Java API for XML Registries)提供了與多種類型注冊服務進行交互的API。JAXR運行客戶端訪問與JAXR規(guī)范相兼容的Web Servcices,這里的Web Services即為注冊服務。一般來說,注冊服務總是以Web Services的形式運行的。JAXR支持三種注冊服務類型:JAXR Pluggable Provider、Registry-specific JAXR Provider、JAXR Bridge Provider(支持UDDI Registry和ebXML Registry/Repository等)。

          · SAAJ

          ????? SAAJ(SOAP with Attachemnts API for Java)是JAX-RPC的一個增強,為進行低層次的SOAP消息操縱提供了支持。

          四. J2EE 的結構

          ????? 這種基于組件,具有平臺無關性的J2EE 結構使得J2EE 程序的編寫十分簡單,因為業(yè)務邏輯被封裝成可復用的組件,并且J2EE 服務器以容器的形式為所有的組件類型提供后臺服務. 因為你不用自己開發(fā)這種服務, 所以你可以集中精力解決手頭的業(yè)務問題.

          ????? 容器和服務

          ????? 容器設置定制了J2EE服務器所提供得內在支持,包括安全,事務管理,JNDI(Java Naming and Directory Interface)尋址,遠程連接等服務,以下列出最重要的幾種服務:

          ????? J2EE安全(Security)模型可以讓你配置 web 組件或enterprise bean ,這樣只有被授權的用戶才能訪問系統(tǒng)資源. 每一客戶屬于一個特別的角色,而每個角色只允許激活特定的方法。你應在enterprise bean的布置描述中聲明角色和可被激活的方法。由于這種聲明性的方法,你不必編寫加強安全性的規(guī)則。

          ????? J2EE 事務管理(Transaction Management)模型讓你指定組成一個事務中所有方法間的關系,這樣一個事務中的所有方法被當成一個單一的單元. 當客戶端激活一個enterprise bean中的方法,容器介入一管理事務。因有容器管理事務,在enterprise bean中不必對事務的邊界進行編碼。要求控制分布式事務的代碼會非常復雜。你只需在布置描述文件中聲明enterprise bean的事務屬性,而不用編寫并調試復雜的代碼。容器將讀此文件并為你處理此enterprise bean的事務。

          ????? JNDI 尋址(JNDI Lookup)服務向企業(yè)內的多重名字和目錄服務提供了一個統(tǒng)一的接口,這樣應用程序組件可以訪問名字和目錄服務.

          ????? J2EE遠程連接(Remote Client Connectivity)模型管理客戶端和enterprise bean間的低層交互. 當一個enterprise bean創(chuàng)建后, 一個客戶端可以調用它的方法就象它和客戶端位于同一虛擬機上一樣.

          ????? 生存周期管理(Life Cycle Management)模型管理enterprise bean的創(chuàng)建和移除,一個enterprise bean在其生存周期中將會歷經幾種狀態(tài)。容器創(chuàng)建enterprise bean,并在可用實例池與活動狀態(tài)中移動他,而最終將其從容器中移除。即使可以調用enterprisebean的create及remove方法,容 器也將會在后臺執(zhí)行這些任務。

          五、企業(yè)級應用示例

          ????? 下面我們通過假設一個企業(yè)應用的J2EE實現(xiàn),來了解各種組件和服務的應用。假設應用對象是計算機產品的生產商/零售商的銷售系統(tǒng),這個銷售系統(tǒng)能夠通過自己的網站發(fā)布產品信息,同時也能將產品目錄傳送給計算機產品交易市場。銷售系統(tǒng)能夠在線接受訂單(來自自己的Web網站或者來自計算機產品交易市場),并隨后轉入內部企業(yè)管理系統(tǒng)進行相關的后續(xù)處理。

          ????? 參見圖1,這個企業(yè)應用可以這種方式架構。該企業(yè)應用的核心是產品目錄管理和產品定購管理這兩個業(yè)務邏輯,使用EJB加以實現(xiàn),并部署在EJB容器中。由于產品目錄和定購信息都需要持久化,因此使用JDBC連接數(shù)據(jù)庫,并使用JTA來完成數(shù)據(jù)庫存取事務。


          圖1 J2EE應用示例

          ????? 然后使用JSP/Servlet來實現(xiàn)應用的Web表現(xiàn):在線產品目錄瀏覽和在線定購。為了將產品目錄發(fā)送給特定的交易市場,使用JMS實現(xiàn)異步的基于消 息的產品目錄傳輸。為了使得更多的其它外部交易市場能夠集成產品目錄和定購業(yè)務,需要使用Web Services技術包裝商業(yè)邏輯的實現(xiàn)。由于產品定購管理需要由公司內部雇員進行處理,因此需要集成公司內部的用戶系統(tǒng)和訪問控制服務以方便雇員的使 用,使用JACC集成內部的訪問控制服務,使用JNDI集成內部的用戶目錄,并使用JAAS進行訪問控制。由于產品訂購事務會觸發(fā)后續(xù)的企業(yè)ERP系統(tǒng)的 相關操作(包括倉儲、財務、生產等),需要使用JCA連接企業(yè)ERP。

          ????? 最后為了將這個應用納入到企業(yè)整體的系統(tǒng)管理體系中去,使用Application Client架構了一個管理客戶端(與其它企業(yè)應用管理應用部署在一臺機器上),并通過JMX管理這個企業(yè)應用。

          ????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ( 摘自中科永聯(lián) 高級技術培訓中心 )

          posted @ 2007-03-14 16:58 Bill111 閱讀(329) | 評論 (0)編輯 收藏
          JUnit測試的理由

          編寫JUnit測試的理由和幾條測試習慣

          ?moneyice 發(fā)表于 2006 年 06 月 19 日

          編寫JUnit測試的理由

          ·JUnit在保證質量的同時提高代碼編寫速度
          看起來不可思議,但是事實。使用JUnit后,花在調試的時間就會更少,在改變代碼的時候更有信心。有了這種信心,你可以在重構代碼,添加新特性的時候更有闖勁。
          如 果沒有測試,那么重構或者添加新特性很容易成為妄想,因為你無法知曉什么地方會被破壞掉。如果擁有完善的測試套,在改變代碼后,立即運行測試,這樣就可以 得到信心,你的改變沒有破壞任何東西。當運行測試時,如果檢測出bug,因為代碼在腦海里還很清楚,所以bug很容易被解決。用JUnit編寫測試,可以 使你的代碼編寫達到極限速度,而且快速定位bug。
          ·JUnit 及其簡單
          測試應該很簡單,這一點很關鍵。如果測試太復雜,花費太多時間,編寫測試就不太值得了。使用JUnit,你可以快速的寫出測試代碼來驗證程序。隨著軟件的增長相應的增加測試代碼。
          使用JUnit,運行測試也變得很簡單而且很快速。
          ·JUnit 驗證它們自己的結果,而且能夠立即反饋
          JUnit測試能夠自動運行,它們檢查自身的結果。運行測試后,你會立即得到可視化的反饋,測試通過或者失敗。不需要手工來輸出測試結果報告。
          ·JUnit 測試可以被組合為不同層次的測試套
          JUnit測試可以被整合到測試套中,測試套可以包含測試用例或者其他的測試套。JUnit測試的組合行為使你可以聚集一組測試用例為一個測試套,也可以將多個測試套組合到一個測試套中。你可以運行任何一個層次的測試套。
          ·編寫 JUnit 測試代價很小
          使用JUnit測試框架,你可以代價很小的編寫測試,而且享受著測試框架提供的便利。寫測試簡單到,就是編寫一個方法,使用一下要測試的代碼,定義一個期望的結果。
          ·JUnit 測試增強了軟件的穩(wěn)定性。測試越少,代碼的穩(wěn)定性就越差。測試驗證了軟件的穩(wěn)定性,保證了更改沒有在項目中引起波紋效應。

          JUnit 測試是程序員的測試。JUnit測試是用來提高程序員的效率和代碼質量。與功能測試不同,功能測試是將整個系統(tǒng)視作黑盒,從整體保證軟件有效。單元測試是 用來測試實現(xiàn)基本功能的代碼塊。程序員編寫并維護JUnit測試代碼。當一次開發(fā)迭代完成,測試代碼也要同步的更新,作為對此次迭代的質量驗證。

          測試習慣

          編寫JUnit測試時,確保以下牢記在心:
          ·只用測試到的地方才會運行的很好。
          ·測一點,寫一點, 測一點,寫一點...
          ·取保所有的測試都要執(zhí)行。
          ·最少每天一次運行所有的測試用例 (或一晚)。
          ·為最有破壞可能性的代碼編寫完善的測試。
          ·為你最有可能獲得回報的地方編寫測試。
          ·如果你總是在調試某個地方,編寫JUnit測試自動驗證結果來代替調試。
          ·如果有bug被報告,編寫測試來暴露這個bug。
          ·有人讓你幫助調試的時候,幫助他寫測試用例。
          ·在編寫代碼之前編寫單元測試代碼,只有測試失敗的時候才寫新代碼。寫最簡單的新代碼讓測試通過。

          ?

          posted @ 2007-03-13 14:18 Bill111 閱讀(1682) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 滁州市| 玛沁县| 英山县| 建湖县| 静乐县| 长顺县| 台南县| 桐乡市| 衡山县| 北京市| 读书| 龙江县| 青冈县| 通江县| 聂拉木县| 台东县| 湾仔区| 车险| 伽师县| 潼南县| 丰城市| 民县| 稷山县| 平乡县| 祁连县| 柳江县| 铁力市| 临潭县| 庆云县| 丘北县| 济宁市| 尚义县| 绍兴县| 桃源县| 普兰县| 米泉市| 黔东| 龙泉市| 五莲县| 奉节县| 贺州市|