隨筆 - 23  文章 - 11  trackbacks - 0
          <2006年9月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          在WebWork2.2中和Spring的結合變得簡單了,WebWork的Action的也可以由Spring來管理。但是如何進行測試了,在google上搜了一下,其代碼都是如下形式:
           1        Map params = new HashMap();
           2        params.put("a""test");
           3               Map paramCtx = new HashMap();
           4        paramCtx.put(ActionContext.PARAMETERS, params);
           5                ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy("/organiz""new_depart", paramCtx, falsefalse);
           6        proxy.setExecuteResult(false);
           7        assertEquals(proxy.execute(), "success");
           8
           9        MyTestAction action = (MyTestAction) proxy.getAction();
          10        assertEquals(action.getA(), "test");

          該代碼執行時會報錯誤,查看了一下源代碼應該加入
          1paramCtx.put(ActionContext.DEV_MODE, Boolean.FALSE);

          其次需要加載spring的applicationContext,代碼如下:
          1SpringObjectFactory objectFactory = new SpringObjectFactory();
          2        ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
          3        objectFactory.setApplicationContext(appContext);
          4        ObjectFactory.setObjectFactory(objectFactory);


          posted @ 2012-02-28 22:53 小小~咖啡豆 閱讀(186) | 評論 (0)編輯 收藏
          1.編譯亂碼,設置編譯的字符集編碼和環境編碼
          <plugin>
                          <groupId>org.apache.maven.plugins</groupId>
                          <artifactId>maven-compiler-plugin</artifactId>
                          <version>2.3.2</version>
                          <configuration>
                              <source>1.4</source>
                              <target>1.4</target>
                              <encoding>UTF-8</encoding>
                          </configuration>
                      </plugin>
          設置環境變量MAVEN_OPTS=-Xms64m -Xmx128m -Dfile.encoding=UTF-8
          2.運行mvn test時亂碼(IDE上運行TestCase時OK,但是運行maven test亂碼,結果測試不通過)修改pom.xml增加如下內容即可
          <plugin>
                          <groupId>org.apache.maven.plugins</groupId>
                          <artifactId>maven-surefire-plugin</artifactId>
                          <version>2.7.2</version>
                          <configuration>
                              <forkMode>once</forkMode>
                              <argLine>-Dfile.encoding=UTF-8</argLine>
                              <systemProperties>
                                  <property>
                                      <name>net.sourceforge.cobertura.datafile</name>
                                      <value>target/cobertura/cobertura.ser</value>
                                  </property>
                              </systemProperties>
                          </configuration>
                      </plugin>
          posted @ 2011-06-30 02:15 小小~咖啡豆 閱讀(1526) | 評論 (1)編輯 收藏
          <title>屏蔽鼠標右鍵、Ctrl+n、shift+F10、F5刷新、退格鍵</title>
          </head>
          <body onkeydown="KeyDown()"
          oncontextmenu="event.returnValue=false">

          <script language="Javascript"><!--
          //屏蔽鼠標右鍵、Ctrl+n、shift+F10、F5刷新、退格鍵
          //Author: meizz(梅花雨) 2002-6-18

          function KeyDown(){
          if ((window.event.altKey)&&
          ((window.event.keyCode==37)|| //屏蔽 Alt+ 方向鍵 ←
          (window.event.keyCode==39))){ //屏蔽 Alt+ 方向鍵 →
          alert("不準你使用ALT+方向鍵前進或后退網頁!");
          event.returnValue=false;
          }

          /* 注:這還不是真正地屏蔽 Alt+ 方向鍵,
          因為 Alt+ 方向鍵彈出警告框時,按住 Alt 鍵不放,
          用鼠標點掉警告框,這種屏蔽方法就失效了。以后若
          有哪位高手有真正屏蔽 Alt 鍵的方法,請告知。*/

          if ((event.keyCode==8) || //屏蔽退格刪除鍵
          (event.keyCode==116)|| //屏蔽 F5 刷新鍵
          (event.ctrlKey && event.keyCode==82)){ //Ctrl + R
          event.keyCode=0;
          event.returnValue=false;
          }
          if ((event.ctrlKey)&&(event.keyCode==78)) //屏蔽 Ctrl+n
          event.returnValue=false;
          if ((event.shiftKey)&&(event.keyCode==121)) //屏蔽 shift+F10
          event.returnValue=false;
          if (window.event.srcElement.tagName == "A" && window.event.shiftKey)
          window.event.returnValue = false; //屏蔽 shift 加鼠標左鍵新開一網頁
          if ((window.event.altKey)&&(window.event.keyCode==115)){ //屏蔽Alt+F4
          window.showModelessDialog("about:blank","","dialogWidth:1px;dialogheight:1px");
          return false;}
          }
          /* 另外可以用 window.open 的方法屏蔽 IE 的所有菜單
          第一種方法:
          window.open("你的.htm", "","toolbar=no,location=no,directories=no,menubar=no,scrollbars=no,resizable=yes,status=no,top=0,left=0")
          第二種方法是打開一個全屏的頁面:
          window.open("你的.asp", "", "fullscreen=yes")
          */
          // --></script>
          <h2 align=center>屏蔽鼠標右鍵、Ctrl+n、shift+F10、F5刷新、退格鍵</h2>
          </body>
          </html>

          <div style="position: absolute; top: 10; right: 10; width: 148; height: 18;cursor:hand">
          <input type="button" name="Button" value="查看源代碼" onClick= 'window.location = "view-source:" + window.location.href'></div>
          posted @ 2008-09-23 16:12 小小~咖啡豆 閱讀(525) | 評論 (0)編輯 收藏

          數據庫測試

          在創建企業級應用的時候,數據層的單元測試因為其復雜性往往被遺棄,Unitils大大降低了測試的復雜性,使得數據庫的測試變得容易并且易維護。已下介紹databasemodule和dbunitmodule進行數據庫的單元測試。

          用dbUnit管理測試數據

          數據庫的測試應該在單元測試數據庫上運行,單元測試數據庫給我們提供了一個完整的并有著很好細粒度控制的測試數據,DbUnitModule是在dbunit的基礎上進一步的為數據庫的測試提供數據集的支持。

          加載測試數據集

          讓我們以UserDAO中一個簡單的方法findByName(檢查姓氏和名字)為例子開始介紹。他的單元測試如下:

          @DataSet

          public class UserDAOTest extends UnitilsJUnit4 {

              @Test

              public void testFindByName() {

                  User result = userDao.findByName("doe", "john");

                  assertPropertyLenEquals("userName", "jdoe", result);

              }

              @Test

              public void testFindByMinimalAge() {

                  List<User> result = userDao.findByMinimalAge(18);        

                  assertPropertyLenEquals("firstName", Arrays.asList("jack"), result);

              }

          }

              @DateSet 注解表示了測試需要尋找dbunit的數據集文件進行加載,如果沒有指明數據集的文件名,則Unitils自動在class文件的同目錄下加載文件名為 className.xml的數據集文件。(這種定義到class上面的數據集稱為class級別的數據集)

              數據集 文件必須是dbunit的FlatXMLDataSet文件格式,其中包含了所要測試的數據。測試數據庫表中所有的內容將會被刪除,然后再插入數據集中的 數據。如果表不屬于數據集中的,哪么該表的數據將不會被刪除。你也可以明確的加入一個空的表元素,例如<MY_TABLE/>(可以達到刪除 測試數據庫表中內容的作用),如果要明確指定一個空的值,那么使用值[null]。

             為UserDAOTest我們創建一個數據集,并放在UserDAOTest.class文件同目錄下。

          <?xml version='1.0' encoding='UTF-8'?>

          <dataset>

              <usergroup name="admin" />  

              <user userName="jdoe"  name="doe"   firstname="john"   userGroup="admin" />

              <usergroup name="sales" />    

              <user userName="smith" name="smith" userGroup="sales" />

              

          </dataset>

             測試運行的時候,首先將刪除掉usergroup表和user表中的所有內容,然后將插入數據集中的內容。其中name為smith的firstname的值將會是null。

             假設testFindByMinimalAge()方法將使用一個特殊的數據集而不是使用class級別的數據集,你可以定義一個UserDAOTest.testFindByMinimalAge.xml 數據集文件并放在測試類的class文件同目錄下。

          <?xml version='1.0' encoding='UTF-8'?>

          <dataset>

              <user userName="jack" age="18" />

              <user userName="jim"  age="17" />

          </dataset>

          這時,你在testFindByMinimalAge()方法使用@DataSet注解,他將覆蓋class級的數據集

          public class UserDAOTest extends UnitilsJUnit4 {

          @Test

          @DataSet("UserDAOTest.testFindByMinimalAge.xml")

          public void testFindByMinimalAge() {

          List<User> result = userDao.findByMinimalAge(18); 

          assertPropertyLenEquals("firstName", Arrays.asList("jack"), result);

          }

          }

          不要過多的使用method級的數據集,因為過多的數據集文件意味著你要花大量的時間去維護,你優先考慮的是使用class級的數據集。

          配置數據集加載策略

          缺省情況下數據集被寫入數據庫采用的是clean insert策略。這就意味著數據在被寫入數據庫的時候是會先刪除數據集中有使用的表的數據,然后在將數據集中的數據寫入數據庫。加載策略是可配額制的,我們通過修改DbUnitModule.DataSet.loadStrategy.default 的屬性值來改變加載策略。假設我們在unitils.properties屬性文件中加入以下內容:

          DbUnitModule.DataSet.loadStrategy.default=org.unitils.dbunit.datasetloadstrategy.InsertLoadStrategy 

          這時加載策略就由clean insert變成了insert,數據已經存在表中將不會被刪除,測試數據只是進行插入操作。

          加載策略也可以使用@DataSet的注解屬性對單獨的一些測試進行配置:

          @DataSet(loadStrategy = InsertLoadStrategy.class) 

          對于那些樹形DbUnit的人來說,配置加載策略實際上就是使用不同的DatabaseOperation,以下是默認支持的加載策略方式:

          CleanInsertLoadStrategy: 先刪除dateSet中有關表的數據,然后再插入數據。

          InsertLoadStrategy: 只插入數據。

          RefreshLoadStrategy: 有同樣key的數據更新,沒有的插入。

          UpdateLoadStrategy: 有同樣key的數據更新,沒有的不做任何操作。

          配置數據集工廠

           在Unitils中數據集文件采用了multischema xml 格式,這是DbUnits的FlatXmlDataSet 格式的擴展。配置文件格式和文件的擴展可以采用DataSetFactory 

          雖然Unitils當前只支持一種數據格式,但是我們可以通過實現DataSetFactory來使用其他文件格式。當你想使用excel而不是xml格式的時候,可以通過unitils.property中的DbUnitModule.DataSet.factory.default 屬性和@DataSet 注解來創建一個DbUnit's XlsDataSet 實例。

          驗證測試結果

          有些時候我們想在測試時完畢后使用數據集來檢查數據庫中的內容,舉個例子當執行完畢一個存儲過程后你想檢查一下啊數據是否更新了沒有。

          下面的例子表示的是禁用到一年內沒有使用過的帳戶

          public class UserDAOTest extends UnitilsJUnit4 { 

              @Test @ExpectedDataSet 

              public void testInactivateOldAccounts() { 

                  userDao.inactivateOldAccounts(); 

              } 

          注意在test方法上增加了一個@ExpectedDataSet 注解。這將指明unitils將使用UserDAOTest.testInactivateOldAccounts-result.xml 這個數據集的內容和數據庫的內容進行比較。

          <?xml version='1.0' encoding='UTF-8'?> 

          <dataset> 

              <user userName="jack" active="true" /> 

              <user userName="jim"  active="false" /> 

          </dataset> 

          根據這個數據集,將會檢查是否有兩條和記錄集的值相同的記錄在數據庫中。而其他的記錄和表將不理會。

          使用的是@DataSet 注解的話,文件名可以明確指出,如果文件名沒有明確指出來,那么文件名將匹配className .methodName -result.xml 

          使用少使用結果數據集,加入新的數據集意味著更多的維護。替代方式是在代碼中執行相同的檢查(如使用一個findactiveusers()方法)。

          使用多模式的數據集

          一個程序不單單只是連接一個數據庫shema。Unitils采用了擴展的數據集xml來定義多schemas下的數據。以下就是一個讀取數據到2個不同的schemas中的例子:

          <?xml version='1.0' encoding='UTF-8'?> 

          <dataset xmlns="SCHEMA_A" xmlns:b="SCHEMA_B"> 

              <user id="1" userName="jack" />     

              <b:role id="1" roleName="admin" /> 

          </dataset> 

          在這個例子中我定義了兩個schemas,SCHEMA_A 和 SCHEMA_B第一個schema,SCHEMA_A 被連接到默認的xml命名空間中,第二個schema,SCHEMA_B 被連接到命名空間b。如果表xml元素的前綴使用了命名空間b,那么該表就是schema SCHEMA_B 中的,如果沒有使用任何的命名空間那么該表將被認為是SCHEMA_A  

          中的。以上例子中測試數據定義了表SCHEMA_A.user SCHEMA_B.role

          如果在數據集中沒有配置一個默認的命名空間,那么將會采用在unitils.properties中的屬性database.schemaNames 的第一個值作為默認的

          database.schemaNames=SCHEMA_A, SCHEMA_B 

          這個配置將SCHEMA_A 作為缺省的schema,這樣你可以簡化數據集的聲明。

          <?xml version='1.0' encoding='UTF-8'?> 

          <dataset xmlns:b="SCHEMA_B"> 

              <user id="1" userName="jack" />     

              <b:role id="1" roleName="admin" /> 

          </dataset> 

          連接測試數據庫 

          在以上所有的例子中,我們都有一件重要的事情沒有做:當我們進行測試的時候,怎樣連接數據庫并得到DataSource

          當測試套件的第一個測試數據庫的案例運行的時候,Unitils將會通過屬性文件創建一個DataSource 的實例來連接你單元測試時的數據庫,以后的測試中都將使用這個DataSource 實例。連接配置的詳細內容如下:

          database.driverClassName=oracle.jdbc.driver.OracleDriver 

          database.url=jdbc:oracle:thin:@yourmachine:1521:YOUR_DB 

          database.userName=john 

          database.password=secret 

          database.schemaNames=test_john 

          配置章節所說的那樣,你可以將連接數據庫的驅動類和url地址配置到unitils.properties 中去,而用戶名,密碼以及schema可以配置到unitils-local.properties 中去,這樣可以讓開發人員連接到自己的單元測試數據庫中進行測試而不會干預到其他的人。

          在屬性或者setter方法前使用注解@TestDataSource ,將會將DataSource 實例注入到測試實例中去,如果你想加入一些代碼或者配置一下你的datasource,你可以做一個抽象類來實現該功能,所有的測試類都繼承該類。一個簡單的例子如下:

          public abstract class BaseDAOTest extends UnitilsJUnit4 { 

              @TestDataSource 

              private DataSource dataSource; 

               

              @Before     

              public void initializeDao() { 

                  BaseDAO dao = getDaoUnderTest(); 

                  dao.setDataSource(dataSource); 

              } 

              protected abstract BaseDAO getDaoUnderTest(); 

          上面的例子采用了注解來取得一個datasource的引用,另外一種方式就是使用DatabaseUnitils.getDataSource() 方法來取得datasource。

          事務

          出于不同的原因,我們的測試都是運行在一個事務中的,其中最重要的原因如下:

          數據庫的很多action都是在事務正常提交后才做,如SELECT FOR UPDATE 和觸發器

          許多項目在測試數據的時候都會填寫一些測試數據,每個測試運行都會修改或者更新了數據,當下一個測試運行的時候,都需要將數據回復到原有的狀態。

          如果使用的是hibernate或者JPA的時候,都需要每個測試都運行在事務中,保證系統的正常工作。

          缺省情況下,事務管理是disabled的,事務的默認行為我們可以通過屬性文件的配置加以改變:

          DatabaseModule.Transactional.value.default=commit 

          采用這個設置,每個的測試都將執行commit,其他的屬性值還有rollback disabled 

          我們也可以通過在測試類上使用注解@Transactional 來改變默認的事務設置,如:

          @Transactional(TransactionMode.ROLLBACK) 

          public class UserDaoTest extends UnitilsJUnit4 { 

          通過這種class上注解的事務管理,可以讓每個測試都確保回滾,@Transactional 注解還可以繼承的,因此我們可以將其放在父類中,而不必每個子類都進行聲明。

          .........

          如果你使用Unitils的spring支持(見使用spring進行測試)你如果配置了PlatformTransactionManager 的bean,那么unitils將會使用這個事務管理。

          posted @ 2008-08-25 15:11 小小~咖啡豆 閱讀(1942) | 評論 (2)編輯 收藏
          1、使用Dir:  
          If   Dir$(dirName,   ATTR_DIRECTORY)   =   ""   Then  
            'Directory   does   not   exist  
          Else  
            'Directory   does   exist  
          End   If  
          2、使用FileSystemObject:  
          Set   objFSO   =   CreateObject("Scripting.FileSystemObject")  
             
          If   objFSO.FolderExists(dirName)   Then  
            'Directory   does   exist  
          Else  
            'Directory   does   not   exist  
          End   If
          posted @ 2008-07-04 10:06 小小~咖啡豆 閱讀(674) | 評論 (0)編輯 收藏

          Unitils模塊

          配置

          和大多數的項目一樣,unitils也需要一些配置,默認情況下有3個配置,每個配置都覆寫前一個的配置

          1. unitils-default.properties 默認的配置,在unitils發行包中。
          2. unitils.properties 可包含項目的全部配置
          3. unitils-local.properties 可以包含用戶特定配置

          第一個配置文件unitils-default.properties,它包含了缺省值并被包含在unitils的發行包中。我們沒有必要對這個文件進行修改,但它可以用來作參考。

          第二個配置文件unitils.properties,它是我們需要進行配置的文件,并且能覆寫缺省的配置。舉個例子,如果你的項目使用的是oracle數據庫,你可以創建一個unitils.properties文件并覆寫相應的driver class和database url。

          database.driverClassName=oracle.jdbc.driver.OracleDriver
          database.url=jdbc:oracle:thin:@yourmachine:1521:YOUR_DB

          這個文件并不是必須的,但是一旦你創建了一個,你就需要將該文件放置在項目的classpath下

          最后一個文件,unitils-local.properties是可選的配置文件,它可以覆寫項目的配置,用來定義開發者的具體設置,舉個例子來說,如果每個開發者都使用自己的數據庫schema,你就可以創建一個unitils-local.properties為每個用戶配置自己的數據庫賬號、密碼和schema。

          database.userName=john
          database.password=secret
          database.schemaNames=test_john

          每個unitils-local.properties文件應該放置在對應的用戶文件夾中(System.getProperty("user.home"))。

          本地文件名unitils-local.properties也可以通過配置文件定義,在unitils.properties覆寫unitils.configuration.localFileName就可以。

          unitils.configuration.localFileName=projectTwo-local.properties

           

          啟用你的unitils

          unitils的功能是依賴于基礎的測試框架,要使用unitils的功能,就必須先enable他們,這樣做的目的也是為了容易擴展。目前支持的框架有:

          1. JUnit3 :org.unitils.UnitilsJUnit3
          2. JUnit4 :org.unitils.UnitilsJUnit4
          3. TestNG:org.unitils.UnitilsTestNG

          舉個例子,如果使用JUnit3,你要使用unitils

          import org.unitils.UnitilsJUnit3;
          public class MyTest extends UnitilsJUnit3 {
          }

          通常你將創建你自己的包含一些公共行為的測試基類,如dataSource的注入,你可以讓這個基類繼承unitils測試類。

          當你使用的是JUnit4的話,你也可是使用@RunWith來代替繼承unitils測試類

          import org.junit.runner.RunWith;
          import org.unitils.UnitilsJUnit4TestClassRunner;
          @RunWith(UnitilsJUnit4TestClassRunner.class)
          public class MyTest {
          }

           

          模塊系統

          在開始舉例之前,讓我們先了解一下unitils概念。

          unitils的結構被設計成了十分容易擴展,每個模塊提供了一種服務,當執行Test的時候通過TestListener調用相應的服務。

          image

          這種設計采用了一個統一的方式提供服務,如果你需要加入其他的服務,無需去改編測試基類(UnitilsJUnit4這些類)。要加入新的服務只需要添加一個新的模塊并在unitls配置文件中登記這個模塊。

          目前unitils中所有有效的模塊如下:

          1. DatabaseModule 數據庫單元測試的維護和連接池。
          2. DbUnitModule 使用DBUnit來管理測試數據。
          3. hibernatemodule 支持Hibernate的配置和自動數據庫映射檢查。
          4. EasyMockModule 支持創建mock和寬松的反射參數匹配。
          5. InjectModule 支持在一個對象中注入另一個對象。
          6. SpringModule 支持加載spring的上下文配置,并檢索和Spring Bean注入。
          posted @ 2008-04-07 00:45 小小~咖啡豆 閱讀(2796) | 評論 (2)編輯 收藏

                單元測試應該是簡單和直觀的,而現實中的項目大多都是采用多層方式的,如EJB和hibernate的數據驅動層的中間件技術。

                unitils來源于一個嘗試,就是希望能以更務實的方式來看待單元測試......

                這個指南會告訴你,什么項目可以使用unitils。 并在這個指導方針頁 中你可以了解到測試的準側和它的特點。如果您想了解如何可以配置unitils ,并得以迅速地啟動,請查看cookbook

          • unitils的斷言
          • unitils的模塊
          • 數據庫的測試
          • 數據庫的自動測試
          • hibernate的測試
          • jpa的測試
          • spring的測試
          • mock object的測試
          • 今后的方向

                unitils的斷言

                在開始這個指南之前我們先說明一下獨立于unitils核心模塊的斷言。在下面的例子中,不需要進行配置,將unitils的jar包和依賴包放在你的classpath下,就可以進行測試了。

                通過反射進行斷言

                一個典型的單元測試包含了結果值和期望值的比較,unitils提供了斷言的方法以幫助你進行該操作,讓我們看看實例2中對有著id、first name、last name屬性的User類的2個實例的比較

          public class User {
              private long id;
              private String first;
              private String last;
          
              public User(long id, String first, String last) {
                  this.id = id;
                  this.first = first;
                  this.last = last;
              }
          }
          
          User user1 = new User(1, "John", "Doe");
          User user2 = new User(1, "John", "Doe");
          assertEquals(user1, user2);
              你期望這個斷言是成功的,因為這兩個實例含有相同的屬性,但是運行的結果并非如此,應為User類并沒有覆寫
          equals()方法,所以assertEquals是對兩個實例是否相等進行判斷(user1 == user2)結果導致了比較的失敗。
              假設你像如下代碼一樣實現了equals方法
          public boolean equals(Object object) {
              if (object instanceof User) {
                  return id == ((User) object).id;
              }
              return false;
          }

                 這在你的程序邏輯中是一個合乎邏輯的實現,當兩個User實例擁有相同的id的時候,那么這兩個實例就是相等的。然而這種方式在你的單元測試中并不合適,并不能通過id的相同來認為兩個user是相同的。

          User user1 = new User(1, "John", "Doe");
          User user2 = new User(1, "Jane", "Smith");
          assertEquals(user1, user2);

                 這個斷言將會成功,但這并不是你所期望的,因此不要使用assertEquals來對兩個對象進行判定是否相等(外覆類和java.lang.String類除外)。要想斷言他們相等,一種方法就是斷言每個屬性相等。

          User user1 = new User(1, "John", "Doe");
          User user2 = new User(1, "John", "Doe");
          assertEquals(user1.getId(), user2.getId());
          assertEquals(user1.getFirst(), user2.getFirst());
          assertEquals(user1.getLast(), user2.getLast());

                 unitils提供了一些方法來幫助你執行斷言更加的簡單,通過反射,使用ReflectionAssert.assertRefEquals上面的代碼重寫如下:

          User user1 = new User(1, "John", "Doe");
          User user2 = new User(1, "John", "Doe");
          assertRefEquals(user1, user2);
             這個斷言將通過反射對兩個實例中的每個屬性都進行比較,先是id、然后是first name、最后是last name。
             如果一個屬性本身也是一個對象,那么將會使用反射進行遞歸比較,這同樣適合與集合、map、和數組之間的比較,他們
          的每個元素會通過反射進行比較。如果值是一個基本類型或者是一個外覆類,那么將會使用==進行值的比較,因此下面的斷
          言會取得成功
          assertRefEquals(1, 1L); 
          
          List<Double> myList = new ArrayList<Double>();
          myList.add(1.0);
          myList.add(2.0);
          assertRefEquals(Arrays.asList(1, 2), myList);

                寬松的斷言

               出于可維護性,這一點是十分重要的,舉例說明:如果你要計算一個帳戶的余額,那你就沒比較檢查這個帳戶的名稱。他只會增加復雜性,使之更難理解。如果你想讓你的測試代碼更容易生存,更容易重構的話,那請確保你斷言的范圍。

                寬松的順序

                在比較集合和數組的時候你可能并不關心他們中元素的順序,通過使用ReflectionAssert.assertRefEquals方法并配合ReflectionComparatorMode.LENIENT_ORDER參數將忽略元素的順序。

          List<Integer> myList = Arrays.asList(3, 2, 1);
          assertRefEquals(Arrays.asList(1, 2, 3), myList, LENIENT_ORDER);
             無視默認
             第二種的從寬方式是使用ReflectionComparatorMode.IGNORE_DEFAULTS模式,當這種模式被設置的時候,java
          的默認值,如null、0、false將會不參與斷言(忽略)。
             舉個例子,如果你有一個User類,該類有著first name,last name,street等屬性,但是你僅僅想對first name
          和street進行檢查而忽略其他的屬性。
          User actualUser   = new User("John", "Doe", new Address("First street", "12", "Brussels"));
          User expectedUser = new User("John",  null, new Address("First street", null,       null));
          assertRefEquals(expectedUser, actualUser, IGNORE_DEFAULTS);

                你所期望忽略的屬性的對象必須放在斷言左邊,如果放在右邊那么依然進行比較。

          assertRefEquals(null, anyObject, IGNORE_DEFAULTS);  // Succeeds
          assertRefEquals(anyObject, null, IGNORE_DEFAULTS);  // Fails

                寬松的日期

                第三種從寬處理是ReflectionComparatorMode.LENIENT_DATES,當兩個日期都是值,或者都是null的時候,實際的日期將會被忽略(即斷言為相等)。

          Date actualDate =   new Date(44444);
          Date expectedDate = new Date();
          assertRefEquals(expectedDate, actualDate, LENIENT_DATES);

                assertLenEquals

                ReflectionAssert還提供了一種斷言,他提供寬松的順序又提供無視的忽略。

          List<Integer> myList = Arrays.asList(3, 2, 1);
          assertLenEquals(Arrays.asList(1, 2, 3), myList); 
          
          assertLenEquals(null, "any");  // Succeeds
          assertLenEquals("any", null);  // Fails

                屬性斷言

                assertLenEqualsassertRefEquals都是比較對象,ReflectionAssert也提供方法對對象的屬性進行比較。(依賴與ONGL)。

                一些屬性比較的例子

          assertPropertyLenEquals("id", 1, user);  //斷言user的id屬性的值是1 
          assertPropertyLenEquals("address.street", "First street", user); //斷言user的address的street屬性

                在這個方式中你期望的值和判定的對象也可以使用集合

          assertPropertyLenEquals("id", Arrays.asList(1, 2, 3), users);
          assertPropertyLenEquals("address.street", Arrays.asList("First street", 
          "Second street", "Third street"), users);
          posted @ 2008-04-05 14:23 小小~咖啡豆 閱讀(2326) | 評論 (5)編輯 收藏
          1. 寫代碼,就一定要寫測試
          2. 不要受單元測試的教條所限
          3. 相信單元測試將會帶來的成果
          4. 統一考慮編碼和測試
          5. 測試比單元代碼重要
          6. 測試的最佳時機是代碼剛寫完之時
          7. 測試不會白費
          8. 當天有瑕疵的測試也比后補的完美測試好
          9. 不好的測試也比沒有測試強
          10. 測試有時可以驗證意圖
          11. 只有傻瓜不用工具
          12. 用好的去測試不好的

          引至:Info中文網站http://www.infoq.com/cn/news/2007/04/savoia-tao-of-testing

          posted @ 2007-04-30 09:59 小小~咖啡豆 閱讀(399) | 評論 (0)編輯 收藏

          實際運用 Tomcat 5.0.19,我們了解在不修改 Tomcat 原始碼的狀況下,使用者透過 Form submit 的資料將一律以 ISO8859-1 處理,程式設計師必須自行將字串將轉換為 Big5(繁體中文) or GB2312/GBK(簡體中文),我們在應用程式中,對所有的 request.getParameter("xx"); 作了 toBig5String() 的處理,理論上,所有的中文問題應該不會出現才對,結果,還是發現某些狀況下,中文還是變成亂碼!

          經過分析整理,我們發現問題出在 QueryString 的解析,以前在 Tomcat 4.x 時代,無論 SUBMIT 時採用 GET or POST,Tomcat server 對 parameters 的處理都採用相同的編碼,但在 Tomcat 5.x 版,不知何故,卻將 QueryString 的解析獨立出來,目前確認,Form 的 Method 採用 GET 及直接將參數寫在 URL 上的中文,上傳到 Tomcat 時,無論如何轉碼,都會變成亂碼,那怕你事先作過 URLEncode 也一樣。

          網站上,有人針對這個問題,建議將所有中文改採用 base64 編碼,到了 server 上,程式將自行土 base64 decode 回來,確保中文不會發生問題。這樣作法當然可以解決這個問題,但是所有網頁變成限定要採用 POST,且程式設計師要隨時分清楚,那個參數是採用 GET 上傳,那個參數是採用 POST 上傳,然後再針對不同的方式採用不同的解析,這樣的程式一點兒移植性都沒有,更別提跨平臺、跨國際語言了。

          研究 Tomcat 的文件及原始碼,我們找到了問題所在及解決的方法,只有按著以下的作法,才能使 Form submit 的資料完全按著 ISO8859-1 的編碼,當然,若是全照著 Tomcat 的文件說明去作,肯定還是不行,你還是得加上這個參數到 server.xml 中才行。

          解決方案

          請先研究 $TOMCAT_HOME/webapps/tomcat-docs/config/http.html 這個說明檔,擷錄重點如下:
          URIEncoding:This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.

          useBodyEncodingForURI:This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitely set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false.

          上述二個 Tomcat 參數,是設定在 server.xml 中的 http <Connector /> 區塊,要解決 QueryString 中文變成亂碼的問題,你必須至少設定這二個參數其中之一。
          URIEncoding 請設定為 URIEncoding="ISO-8859-1" 指定為 "ISO-8859-1" 編碼,讓 QueryString 的字元編碼與 post body 相同。
          useBodyEncodingForURI 這是用來相容 Tomcat 4.x 版的,設定的值是 "true" or "false",意思是指 "要不要讓 QueryString 與 POST BODY 採用相同的字元編碼 ?",若是設成 true,那也可達到 "ISO-8859-1" 編碼的需求。
          建議,採用 URIEncoding 的設定,畢竟 useBodyEncodingForURI 的作法是為了相容 Tomcat 4.X。不過若照原文的說明,理論上這二個參數都不設,Tomcat 也該採用 "ISO-8859-1" 的編碼,那為什麼還是會有問題呢 ? 我們由 Tomcat Source Code 來看就清楚了。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          // 這一段碼是 Tomcat 用來解 QueryString 的程式,
          // 在 org.apache.tomcat.util.http.Parameters 這個 class 裡。
          private String urlDecode(ByteChunk bc, String enc)
            throws IOException {
            if( urlDec==null ) {
               urlDec=new UDecoder(); 
            }
            urlDec.convert(bc);
            String result = null;
            if (enc != null) {
              bc.setEncoding(enc);
              result = bc.toString();
            } 
            else {
              CharChunk cc = tmpNameC;
              cc.allocate(bc.getLength(), -1);
              // Default encoding: fast conversion
              byte[] bbuf = bc.getBuffer();
              char[] cbuf = cc.getBuffer();
              int start = bc.getStart();
              for (int i = 0; i < bc.getLength(); i++) {
                cbuf[i] = (char) (bbuf[i + start] & 0xff);
              }
              cc.setChars(cbuf, 0, bc.getLength());
              result = cc.toString();
              cc.recycle();
            }
            return result;
          }
          

          請特別注意紅色區塊,當 Tomcat 發現 QueryString 並沒有設定 encode 時,並非像文件中所說預設採用 ISO-8859-1 的編碼,而是用一段 fast conversion 來處理,才會造成中文問題,所以,還是必須在 Server.xml 中,加上 URLEncoding 的參數設定才行哦。

          Connector 的設定範例:
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          <Connector
          debug="0"
          acceptCount="100"
          connectionTimeout="20000"
          disableUploadTimeout="true"
          port="80"
          redirectPort="8443"
          enableLookups="false"
          minSpareThreads="25"
          maxSpareThreads="75"
          maxThreads="150"
          maxPostSize="0"
          URIEncoding="ISO-8859-1"
          >
          </Connector>
          

          文章來至:http://www.javaworld.com.tw/jute/post/view?bid=9&id=44042&sty=1&tpg=1&age=0
          posted @ 2007-04-26 10:33 小小~咖啡豆 閱讀(7028) | 評論 (0)編輯 收藏

          絕對的最強的java ide的7.0M1已經出了,快去試試把,
          http://www.jetbrains.com/idea/nextversion/

          posted @ 2007-04-12 09:07 小小~咖啡豆 閱讀(291) | 評論 (0)編輯 收藏

          http://www.jscud.com/srun/news/viewhtml/4_2005_1/26.htm

          posted @ 2007-03-28 15:36 小小~咖啡豆 閱讀(1461) | 評論 (0)編輯 收藏

          用StrutsTestCase能很好的對Struts來進行測試,可是如果時用Spring來管理Struts的action的時候,用StrutsTestCase的常規方式是不能進行測試的,以下的一個文章對此有很好的說明:

          http://www.jetmaven.net/contents/documents/p_spring_junit_combination.php

          posted @ 2007-03-25 23:07 小小~咖啡豆 閱讀(440) | 評論 (0)編輯 收藏

          webwork的IOC(基于2.1.X版本)
          webwork的ioc其實在webwork中使用起來挺方便的,雖然其功能不算強大,但是已經能很好的滿足我們一般的需要了,就算我們使用spring 的ioc,如果不使用特別的功能,其一般我們也是基于接口,然后有個set方法,通過set來注入,沒有太多的區別,不同的是webwork的ioc需要依賴xwork,而spring卻是依賴spring這個容器。
          webwork的ioc是怎么進行注入的了,我們從代碼中進行分析:
          首先看看攔截器的代碼:

          public class ComponentInterceptor extends AroundInterceptor {
          //~ Static fields/initializers /////////////////////////////////////////////

          public static final String COMPONENT_MANAGER = "com.opensymphony.xwork.interceptor.component.ComponentManager";

          //~ Methods ////////////////////////////////////////////////////////////////

          protected void after(ActionInvocation dispatcher, String result) throws Exception {
          }

          protected void before(ActionInvocation dispatcher) throws Exception {
          ComponentManager container = (ComponentManager) ActionContext.getContext().get(COMPONENT_MANAGER);

          if (container != null) {
          container.initializeObject(dispatcher.getAction());
          }
          }
          }

          主要的代碼用黑體標注出來了,container實際就是組件管理器,這里是一個ComponentManager接口的實現 DefaultComponentManager,然后調用了該類的方法initializeObject(dispatcher.getAction ());而dispatcher.getAction()實際就是所調用的action對象,我們再來看看 DefaultComponentManager做了什么。

          public void initializeObject(Object obj) {
          loadResource(obj, obj.getClass(), this);
          }


          private Class loadResource(Object resource, Class clazz, DefaultComponentManager dcm) {
          // ~由此來判斷是否要進行依賴注入
          boolean resourceNotLoaded = !dcm.loadOrder.contains(resource);

          if (resourceNotLoaded) {
          Map resources = getResourceDependencies(clazz);

          for (Iterator iterator = resources.entrySet().iterator();
          iterator.hasNext();) {
          Map.Entry mapEntry = (Map.Entry) iterator.next();
          Class depResource = (Class) mapEntry.getKey();
          DefaultComponentManager newDcm = (DefaultComponentManager) mapEntry.getValue();

          try {
          ResourceEnablerPair pair = setupAndOptionallyCreateResource(newDcm, depResource);
          setupResource(resource, pair.enabler, pair.resource);
          } catch (Exception e) {
          e.printStackTrace();

          if (log.isDebugEnabled()) {
          log.debug("Error loading or setting up resource: " + resources.getClass().getName(), e);
          }
          }
          }

          dcm.alreadyLoaded.add(clazz);

          if (resource instanceof Initializable) {
          Initializable initializable = (Initializable) resource;
          initializable.init();
          }

          dcm.resourceInstances.put(clazz, resource);
          dcm.loadOrder.add(resource);
          }

          // now return this class's enabler
          Class enabler = (Class) dcm.enablers2.get(clazz);

          return enabler;
          }

          private Map getResourceDependencies(Class resourceClass) {
          List interfaces = new ArrayList();
          //~ 將所有的interface放入interfaces鏈表中
          addAllInterfaces(resourceClass, interfaces);

          Map dependencies = new HashMap();

          for (Iterator iterator = interfaces.iterator(); iterator.hasNext();) {
          Class anInterface = (Class) iterator.next();

          DefaultComponentManager dcm = this;

          while (dcm != null) {
          Class possibleResource = (Class) dcm.enablers.get(anInterface);

          if (possibleResource != null) {
          dependencies.put(possibleResource, dcm);

          break;
          }
          dcm = dcm.fallback;
          }
          }
          return dependencies;
          }

          private void addAllInterfaces(Class clazz, List allInterfaces) {
          if (clazz == null) {
          return;
          }

          Class[] interfaces = clazz.getInterfaces();
          allInterfaces.addAll(Arrays.asList(interfaces));
          addAllInterfaces(clazz.getSuperclass(), allInterfaces);
          }

          重要的代碼都用黑體進行了標注,方法initializeObject中所調用的loadResource(obj, obj.getClass(), this);就執行了查找接口,并注入接口實現類整個過程。
          loadResource首先調用了getResourceDependencies(clazz);getResourceDependencies又調用了addAllInterfaces(resourceClass, interfaces);addAllInterfaces作用就是取得這個類包括這個類的父類的所有實現的接口,而getResourceDependencies方法就是對這個接口進行過濾,返回只是在配置中有的接口。setupAndOptionallyCreateResource(newDcm, depResource);進行的就是創建這些接口的實現類的對象,這個代碼的內容如下:

          private ResourceEnablerPair setupAndOptionallyCreateResource(DefaultComponentManager newDcm, Class depResource) throws Exception {
          ResourceEnablerPair pair = new ResourceEnablerPair();
          Object newResource = newDcm.resourceInstances.get(depResource);

          if (newResource == null) {
          newResource = ObjectFactory.getObjectFactory().buildBean(depResource);
          }

          pair.resource = newResource;

          Class enabler = loadResource(newResource, depResource, newDcm);
          pair.enabler = enabler;

          return pair;
          }

          因為準備創建出來的接口實現類對象的接口可能又實現了其他的接口,因此再調用了loadResource(newResource, depResource, newDcm)。對象創建了,然后就是注入這個對象,setupResource(resource, pair.enabler, pair.resource)就是起這個作用的。代碼如下:

          private void setupResource(Object resource, Class enabler, Object newResource) {
          if (enabler == null) {
          return;
          }

          try {
          enabler.getMethods()[0].invoke(resource, new Object[] {newResource});
          } catch (Exception e) {
          e.printStackTrace();

          if (log.isDebugEnabled()) {
          log.debug("Error invoking method for resource: " + resource.getClass().getName(), e);
          }
          }
          }

          每個接口只有一個set方法,通過反射機制調用這個方法將創建出來的接口實現對象注入進去。整個IOC就完成了。

          posted @ 2007-03-22 10:30 小小~咖啡豆 閱讀(333) | 評論 (0)編輯 收藏

          http://www.scriptviewer.com/story.php?title=IntelliJ-IDEA-60-aeae

          posted @ 2007-03-11 00:43 小小~咖啡豆 閱讀(344) | 評論 (0)編輯 收藏

          Idea6.0默認是用的自帶的jdk5啟動的,如果想用jdk6可以按如下辦法操作:


          1.將idea目錄下的jre目錄改名
          2.將安裝jdk6目錄中的jre目錄拷貝到idea目錄下,然后在將jdk6目錄中的jdk\lib\tools.jar拷貝到jre\lib下
          3.修改idea.exe.vmoptions文件中的啟動參數(這個不是必須的,只是提高idea的響應速度)
          posted @ 2007-02-01 08:09 小小~咖啡豆 閱讀(450) | 評論 (0)編輯 收藏

          C/C++ Source Add Block Comment Ctrl+Shift+/ C/C++ Editor
          C/C++ Source Add Include Ctrl+Shift+N C/C++ Editor
          C/C++ Source Comment Ctrl+/ C/C++ Editor
          C/C++ Source Find Declaration Ctrl+G C/C++ Editor
          C/C++ Source Find References Ctrl+Shift+G C/C++ Editor
          C/C++ Source Format Ctrl+Shift+F C/C++ Editor
          C/C++ Source Go to Matching Bracket Ctrl+Shift+P C/C++ Editor
          C/C++ Source Go to next C/C++ member Ctrl+Shift+向下鍵 C/C++ Editor
          C/C++ Source Go to previous C/C++ member Ctrl+Shift+向上鍵 C/C++ Editor
          C/C++ Source Open Declaration F3 C/C++ Editor
          C/C++ Source Open Definition Ctrl+F3 C/C++ Editor
          C/C++ Source Open Type Ctrl+Shift+T C/C++ Editor
          C/C++ Source Remove Block Comment Ctrl+Shift+\ C/C++ Editor
          C/C++ Source Show outline Ctrl+O C/C++ Editor
          C/C++ Source Uncomment Ctrl+\ C/C++ Editor
          Makefile Source Comment Ctrl+/ Makefile Editor
          Makefile Source Open declaration F3 Makefile Editor
          Makefile Source Uncomment Ctrl+\ Makefile Editor
          Refactor - C/C++ Redo - Refactoring Alt+Shift+Y C/C++ Editor
          Refactor - C/C++ Rename - Refactoring Alt+Shift+R C/C++ Editor
          Refactor - C/C++ Undo - Refactoring Alt+Shift+Z C/C++ Editor
          View Zoom In Ctrl+= 在窗口中
          View Zoom Out Ctrl+- 在窗口中
          搜索 工作空間中的聲明 Ctrl+G 在窗口中
          搜索 工作空間中的引用 Ctrl+Shift+G 在窗口中
          搜索 打開"搜索"對話框 Ctrl+H 在窗口中
          搜索 顯示"文件中的出現位置"快速菜單 Ctrl+Shift+U 在窗口中
          文件 "新建"菜單 Alt+Shift+N 在窗口中
          文件 保存 Ctrl+S 在窗口中
          文件 全部保存 Ctrl+Shift+S 在窗口中
          文件 全部關閉 Ctrl+Shift+F4 在窗口中
          文件 全部關閉 Ctrl+Shift+W 在窗口中
          文件 關閉 Ctrl+F4 在窗口中
          文件 關閉 Ctrl+W 在窗口中
          文件 刷新 F5 在窗口中
          文件 屬性 Alt+Enter 在窗口中
          文件 打印 Ctrl+P 在窗口中
          文件 新建 Ctrl+N 在窗口中
          文件 重命名 F2 在窗口中
          文本編輯 上一個詞語 Ctrl+左箭頭 編輯文本
          文本編輯 上滾行 Ctrl+向上鍵 編輯文本
          文本編輯 下一個詞語 Ctrl+右箭頭 編輯文本
          文本編輯 下滾行 Ctrl+向下鍵 編輯文本
          文本編輯 全部展開 Ctrl+Numpad_Multiply 編輯文本
          文本編輯 切換折疊 Ctrl+Numpad_Divide 編輯文本
          文本編輯 刪除上一個詞語 Ctrl+Backspace 編輯文本
          文本編輯 刪除下一個詞語 Ctrl+Delete 編輯文本
          文本編輯 刪除至行末 Ctrl+Shift+Delete 編輯文本
          文本編輯 刪除行 Ctrl+D 編輯文本
          文本編輯 在當前行上面插入行 Ctrl+Shift+Enter 編輯文本
          文本編輯 在當前行下面插入行 Shift+Enter 編輯文本
          文本編輯 復制行 Ctrl+Alt+向下鍵 編輯文本
          文本編輯 將行上移 Alt+向上鍵 編輯文本
          文本編輯 將行下移 Alt+向下鍵 編輯文本
          文本編輯 展開 Ctrl+Numpad_Add 編輯文本
          文本編輯 折疊 Ctrl+Numpad_Subtract 編輯文本
          文本編輯 改寫切換 Insert 編輯文本
          文本編輯 更改為大寫 Ctrl+Shift+X 編輯文本
          文本編輯 更改為小寫 Ctrl+Shift+Y 編輯文本
          文本編輯 選擇上一個詞語 Ctrl+Shift+左箭頭 編輯文本
          文本編輯 選擇下一個詞語 Ctrl+Shift+右箭頭 編輯文本
          文本編輯 重復行 Ctrl+Alt+向上鍵 編輯文本
          查看 Java 包資源管理器 Alt+Shift+Q,P 在窗口中
          查看 Java 聲明 Alt+Shift+Q,D 在窗口中
          查看 Java 類型層次結構 Alt+Shift+Q,T 在窗口中
          查看 Javadoc Alt+Shift+Q,J 在窗口中
          查看 變量 Alt+Shift+Q,V 在窗口中
          查看 同步 Alt+Shift+Q,Y 在窗口中
          查看 備忘單 Alt+Shift+Q,H 在窗口中
          查看 控制臺 Alt+Shift+Q,C 在窗口中
          查看 搜索 Alt+Shift+Q,S 在窗口中
          查看 斷點 Alt+Shift+Q,B 在窗口中
          查看 顯示視圖 (查看: 大綱) Alt+Shift+Q,O 在窗口中
          查看 顯示視圖 (查看: 問題) Alt+Shift+Q,X 在窗口中
          瀏覽 &Quick Cross References Alt+Shift+P 編輯 Java 源代碼
          瀏覽 Open AspectJ Type Alt+Shift+A 在窗口中
          瀏覽 Open AspectJ Type in Hierarchy Alt+Shift+H 在窗口中
          瀏覽 "顯示位置"菜單 Alt+Shift+W 在窗口中
          瀏覽 上一個編輯位置 Ctrl+Q 在窗口中
          瀏覽 下一頁 Ctrl+. 在窗口中
          瀏覽 前一頁 Ctrl+, 在窗口中
          瀏覽 前移歷史記錄 Alt+右箭頭 在窗口中
          瀏覽 后退歷史記錄 Alt+左箭頭 在窗口中
          瀏覽 在層次結構中打開類型 Ctrl+Shift+H 在窗口中
          瀏覽 快速大綱 Ctrl+O 編輯 Java 源代碼
          瀏覽 快速層次結構 Ctrl+T 編輯 Java 源代碼
          瀏覽 打開聲明 F3 在窗口中
          瀏覽 打開外部 Javadoc Shift+F2 在窗口中
          瀏覽 打開類型 Ctrl+Shift+T 在窗口中
          瀏覽 打開類型層次結構 F4 在窗口中
          瀏覽 打開結構 Ctrl+F3 編輯 Java 源代碼
          瀏覽 打開調用層次結構 Ctrl+Alt+H 在窗口中
          瀏覽 打開資源 Ctrl+Shift+R 在窗口中
          瀏覽 轉至上一個成員 Ctrl+Shift+向上鍵 編輯 Java 源代碼
          瀏覽 轉至下一個成員 Ctrl+Shift+向下鍵 編輯 Java 源代碼
          瀏覽 轉至匹配的方括號 Ctrl+Shift+P 編輯 Java 源代碼
          瀏覽 轉至行 Ctrl+L 編輯文本
          源代碼 切換 Ant 標記出現 Alt+Shift+O 編輯 Ant 構建文件
          源代碼 切換標記出現 Alt+Shift+O 編輯 Java 源代碼
          源代碼 切換注釋 Ctrl+/ 編輯 Java 源代碼
          源代碼 切換注釋 Ctrl+7 編輯 Java 源代碼
          源代碼 切換注釋 Ctrl+Shift+C 編輯 Java 源代碼
          源代碼 在文件中重命名 Alt+Shift+R 編輯 Ant 構建文件
          源代碼 快速輔助 - 在文件中重命名 Ctrl+2,R 編輯 Java 源代碼
          源代碼 快速輔助 - 指定給字段 Ctrl+2,F 編輯 Java 源代碼
          源代碼 快速輔助 - 指定給局部變量 Ctrl+2,L 編輯 Java 源代碼
          源代碼 打開外部文檔 Shift+F2 編輯 Ant 構建文件
          源代碼 顯示工具提示描述 F2 編輯 Ant 構建文件
          源代碼 顯示源代碼快速菜單 Alt+Shift+S 在窗口中
          源代碼 格式 Ctrl+Shift+F 編輯 Ant 構建文件
          源代碼 格式化 Ctrl+Shift+F 編輯 Java 源代碼
          源代碼 添加 Javadoc 注釋 Alt+Shift+J 在窗口中
          源代碼 添加塊注釋 Ctrl+Shift+/ 編輯 Java 源代碼
          源代碼 添加導入 Ctrl+Shift+M 編輯 Java 源代碼
          源代碼 組織導入 Ctrl+Shift+O 在窗口中
          源代碼 縮進行 Ctrl+I 編輯 Java 源代碼
          源代碼 除去出現注釋 Alt+Shift+U 編輯 Java 源代碼
          源代碼 除去塊注釋 Ctrl+Shift+\ 編輯 Java 源代碼
          源代碼 添加 try catch 塊 Alt+Shift+Z + Y 編輯 Java 源代碼

          窗口 上一個編輯器 Ctrl+Shift+F6 在窗口中
          窗口 上一個視圖 Ctrl+Shift+F7 在窗口中
          窗口 上一個透視圖 Ctrl+Shift+F8 在窗口中
          窗口 下一個編輯器 Ctrl+F6 在窗口中
          窗口 下一個視圖 Ctrl+F7 在窗口中
          窗口 下一個透視圖 Ctrl+F8 在窗口中
          窗口 切換至編輯器 Ctrl+Shift+E 在窗口中
          窗口 將活動視圖或編輯器最大化 Ctrl+M 在窗口中
          窗口 打開編輯器下拉列表 Ctrl+E 在窗口中
          窗口 顯示標尺上下文菜單 Ctrl+F10 編輯文本
          窗口 顯示系統菜單 Alt+- 在窗口中
          窗口 顯示視圖菜單 Ctrl+F10 在窗口中
          窗口 顯示鍵輔助 Ctrl+Shift+L 在對話框和窗口中
          窗口 激活編輯器 F12 在窗口中
          編輯 Add Block Comment Ctrl+Shift+/ Editing in Structured Text Editors
          編輯 Format Active Elements Ctrl+I Editing in Structured Text Editors
          編輯 Format Document Ctrl+Shift+F Editing in Structured Text Editors
          編輯 Move Alt+Shift+V Editing JSP Source
          編輯 Occurrences in File Ctrl+Shift+A Editing in Structured Text Editors
          編輯 Open Selection F3 Editing in Structured Text Editors
          編輯 Quick Fix Ctrl+1 Editing in Structured Text Editors
          編輯 Remove Block Comment Ctrl+Shift+\ Editing in Structured Text Editors
          編輯 Rename Alt+Shift+R Editing JSP Source
          編輯 Rename XSD element Alt+Shift+R Editing XSD context
          編輯 Restore Last Selection Alt+Shift+向下鍵 Editing in Structured Text Editors
          編輯 Select Enclosing Element Alt+Shift+向上鍵 Editing in Structured Text Editors
          編輯 Select Next Element Alt+Shift+右箭頭 Editing in Structured Text Editors
          編輯 Select Previous Element Alt+Shift+左箭頭 Editing in Structured Text Editors
          編輯 Show Tooltip Description F2 Editing in Structured Text Editors
          編輯 Toggle Comment Ctrl+Shift+C Editing in Structured Text Editors
          編輯 "快速差別"開關 Ctrl+Shift+Q 編輯文本
          編輯 上下文信息 Alt+? 在窗口中
          編輯 上下文信息 Alt+Shift+? 在窗口中
          編輯 內容輔助 Alt+/ 在對話框和窗口中
          編輯 切換插入方式 Ctrl+Shift+Insert 編輯文本
          編輯 刪除 Delete 在窗口中
          編輯 剪切 Ctrl+X 在對話框和窗口中
          編輯 剪切 Shift+Delete 在對話框和窗口中
          編輯 增量查找 Ctrl+J 編輯文本
          編輯 增量逆向查找 Ctrl+Shift+J 編輯文本
          編輯 復制 Ctrl+C 在對話框和窗口中
          編輯 復制 Ctrl+Insert 在對話框和窗口中
          編輯 復原上一個選擇 Alt+Shift+向下鍵 編輯 Java 源代碼
          編輯 快速修正 Ctrl+1 在窗口中
          編輯 撤消 Ctrl+Z 在窗口中
          編輯 文字補全 Ctrl+Alt+/ 編輯文本
          編輯 顯示工具提示描述 F2 編輯 Java 源代碼
          編輯 查找上一個 Ctrl+Shift+K 編輯文本
          編輯 查找下一個 Ctrl+K 編輯文本
          編輯 查找并替換 Ctrl+F 在窗口中
          編輯 粘貼 Ctrl+V 在對話框和窗口中
          編輯 粘貼 Shift+Insert 在對話框和窗口中
          編輯 選擇上一個元素 Alt+Shift+左箭頭 編輯 Java 源代碼
          編輯 選擇下一個元素 Alt+Shift+右箭頭 編輯 Java 源代碼
          編輯 選擇全部 Ctrl+A 在對話框和窗口中
          編輯 選擇外層元素 Alt+Shift+向上鍵 編輯 Java 源代碼
          編輯 重做 Ctrl+Y 在窗口中
          運行/調試 Debug AspectJ/Java Application Alt+Shift+D,C 在窗口中
          運行/調試 Debug on Server Alt+Shift+D,R 在窗口中
          運行/調試 EOF Ctrl+Z 在控制臺中
          運行/調試 Profile on Server Alt+Shift+P,R 在窗口中
          運行/調試 Run AspectJ/Java Application Alt+Shift+X,C 在窗口中
          運行/調試 Run on Server Alt+Shift+X,R 在窗口中
          運行/調試 切換單步執行過濾器 Shift+F5 在窗口中
          運行/調試 切換行斷點 Ctrl+Shift+B 在窗口中
          運行/調試 單步跳入 F5 調試
          運行/調試 單步跳入選擇的內容 Ctrl+F5 調試
          運行/調試 單步跳過 F6 調試
          運行/調試 單步返回 F7 調試
          運行/調試 執行 Ctrl+U 在窗口中
          運行/調試 顯示 Ctrl+Shift+D 在對話框和窗口中
          運行/調試 檢查 Ctrl+Shift+I 在對話框和窗口中
          運行/調試 繼續 F8 調試
          運行/調試 調試 Ant 構建 Alt+Shift+D,Q 在窗口中
          運行/調試 調試 Eclipse 應用程序 Alt+Shift+D,E 在窗口中
          運行/調試 調試 JUnit 插件測試 Alt+Shift+D,P 在窗口中
          運行/調試 調試 JUnit 測試 Alt+Shift+D,T 在窗口中
          運行/調試 調試 Java Applet Alt+Shift+D,A 在窗口中
          運行/調試 調試 Java 應用程序 Alt+Shift+D,J 在窗口中
          運行/調試 調試 SWT 應用程序 Alt+Shift+D,S 在窗口中
          運行/調試 調試上次啟動 F11 在窗口中
          運行/調試 運行 Ant 構建 Alt+Shift+X,Q 在窗口中
          運行/調試 運行 Eclipse 應用程序 Alt+Shift+X,E 在窗口中
          運行/調試 運行 JUnit 插件測試 Alt+Shift+X,P 在窗口中
          運行/調試 運行 JUnit 測試 Alt+Shift+X,T 在窗口中
          運行/調試 運行 Java Applet Alt+Shift+X,A 在窗口中
          運行/調試 運行 Java 應用程序 Alt+Shift+X,J 在窗口中
          運行/調試 運行 SWT 應用程序 Alt+Shift+X,S 在窗口中
          運行/調試 運行上次啟動 Ctrl+F11 在窗口中
          運行/調試 運行至行 Ctrl+R 調試
          重構 - Java 內聯 Alt+Shift+I 在窗口中
          重構 - Java 將局部變量轉換為字段 Alt+Shift+F 編輯 Java 源代碼
          重構 - Java 抽取局部變量 Alt+Shift+L 在窗口中
          重構 - Java 抽取方法 Alt+Shift+M 在窗口中
          重構 - Java 撤銷 - 重構 Alt+Shift+Z 在窗口中
          重構 - Java 顯示重構快速菜單 Alt+Shift+T 在窗口中
          重構 - Java 更改方法特征符 Alt+Shift+C 在窗口中
          重構 - Java 移動 - 重構 Alt+Shift+V 在窗口中
          重構 - Java 重做 - 重構 Alt+Shift+Y 在窗口中
          重構 - Java 重命名 - 重構 Alt+Shift+R 在窗口中
          項目 全部構建 Ctrl+B 在窗口中

          posted @ 2006-12-31 11:17 小小~咖啡豆 閱讀(230) | 評論 (0)編輯 收藏

          JDK的開源已經發布了
          https://openjdk.dev.java.net/

          posted @ 2006-11-14 08:08 小小~咖啡豆 閱讀(474) | 評論 (0)編輯 收藏

          common mail是一個小而方便的mail包,他實現了對Java Mail的封裝,使用起來十分的方便,但是我在使用他的時候發現,使用純文本的內容發送,結果是亂碼,代碼如下:
          public class TestCommonMail {
          public static void main(String[] args) throws EmailException, MessagingException {
          SimpleEmail email = new SimpleEmail();
          email.setCharset("GB2312");
          email.setHostName("smtp.163.com");
          email.setSubject("test");
          email.addTo("test@163.com");
          email.setFrom("test@163.com");
          email.setMsg("我的測試");
          email.setAuthentication("test", "test");
          email.send();
          }
          }

          分析了一下commons mail的源碼找到了原因。源碼如下:
          public class SimpleEmail extends Email
          {
          public Email setMsg(String msg) throws EmailException, MessagingException
          {
          if (EmailUtils.isEmpty(msg))
          {
          throw new EmailException("Invalid message supplied");
          }

          setContent(msg, TEXT_PLAIN);
          return this;
          }
          }

          Email代碼片段
          public void setContent(Object aObject, String aContentType)
          {
          this.content = aObject;
          if (EmailUtils.isEmpty(aContentType))
          {
          this.contentType = null;
          }
          else
          {
          // set the content type
          this.contentType = aContentType;

          // set the charset if the input was properly formed
          String strMarker = "; charset=";
          int charsetPos = aContentType.toLowerCase().indexOf(strMarker);
          if (charsetPos != -1)
          {
          // find the next space (after the marker)
          charsetPos += strMarker.length();
          int intCharsetEnd =
          aContentType.toLowerCase().indexOf(" ", charsetPos);

          if (intCharsetEnd != -1)
          {
          this.charset =
          aContentType.substring(charsetPos, intCharsetEnd);
          }
          else
          {
          this.charset = aContentType.substring(charsetPos);
          }
          }
          }
          }

          email.send();的send方法將調用
          public void buildMimeMessage() throws EmailException
          {
          try
          {
          this.getMailSession();
          this.message = new MimeMessage(this.session);

          if (EmailUtils.isNotEmpty(this.subject))
          {
          if (EmailUtils.isNotEmpty(this.charset))
          {
          this.message.setSubject(this.subject, this.charset);
          }
          else
          {
          this.message.setSubject(this.subject);
          }
          }

          // ========================================================
          // Start of replacement code
          if (this.content != null)
          {
          this.message.setContent(this.content, this.contentType);
          }
          // end of replacement code
          // ========================================================
          else if (this.emailBody != null)
          {
          this.message.setContent(this.emailBody);
          }
          else
          {
          this.message.setContent("", Email.TEXT_PLAIN);
          }

          if (this.fromAddress != null)
          {
          this.message.setFrom(this.fromAddress);
          }
          else
          {
          throw new EmailException("Sender address required");
          }

          if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0)
          {
          throw new EmailException(
          "At least one receiver address required");
          }

          if (this.toList.size() > 0)
          {
          this.message.setRecipients(
          Message.RecipientType.TO,
          this.toInternetAddressArray(this.toList));
          }

          if (this.ccList.size() > 0)
          {
          this.message.setRecipients(
          Message.RecipientType.CC,
          this.toInternetAddressArray(this.ccList));
          }

          if (this.bccList.size() > 0)
          {
          this.message.setRecipients(
          Message.RecipientType.BCC,
          this.toInternetAddressArray(this.bccList));
          }

          if (this.replyList.size() > 0)
          {
          this.message.setReplyTo(
          this.toInternetAddressArray(this.replyList));
          }

          if (this.headers.size() > 0)
          {
          Iterator iterHeaderKeys = this.headers.keySet().iterator();
          while (iterHeaderKeys.hasNext())
          {
          String name = (String) iterHeaderKeys.next();
          String value = (String) headers.get(name);
          this.message.addHeader(name, value);
          }
          }

          if (this.message.getSentDate() == null)
          {
          this.message.setSentDate(getSentDate());
          }

          if (this.popBeforeSmtp)
          {
          Store store = session.getStore("pop3");
          store.connect(this.popHost, this.popUsername, this.popPassword);
          }
          }
          catch (MessagingException me)
          {
          throw new EmailException(me);
          }
          }
          由代碼可以知道純文本方式最終調用了Java Mail的
          message.setContent(this.content, this.contentType);
          content是內容
          contentType是類型,如text/plain,
          (我們可以試試直接用Java mail發郵件,設置文本內容不使用setText方法,也使用setContent("測試", "text/plain")方式,你可以看到內容也是亂碼)
          關鍵就在于text/plain,我們改成text/plain;charset=gb2312,ok亂碼解決了。在commons mail我們看SimpleEmail 類中setMsg方法調用的就是 setContent(msg, TEXT_PLAIN);我們只需要將Email類中的常量TEXT_PLAIN修改一下加入 charset=你的字符集 ,重新打包jar,這樣就可以了

          posted @ 2006-09-18 09:54 小小~咖啡豆 閱讀(1372) | 評論 (0)編輯 收藏

          package org.wzywjy.mail;

          import java.util.Date;
          import java.util.Properties;
          import javax.mail.Message;
          import javax.mail.MessagingException;
          import javax.mail.Session;
          import javax.mail.Transport;
          import javax.mail.internet.AddressException;
          import javax.mail.internet.InternetAddress;
          import javax.mail.internet.MimeMessage;

          public class TestMail {

          public final static String SMTPSERVER = "smtp.163.com";
          public final static String POPSERVER = "pop.163.com";
          public final static String ACCOUNT = "test";
          public final static String PWD = "test";
          public final static String MAILADDR = "test@163.com";

          public void sendMail(String to, String from, String subject, String body) throws AddressException, MessagingException {
          Properties pro = System.getProperties();
          pro.put("mail.smtp.host", SMTPSERVER);
          pro.put("mail.smtp.auth", "true");
          Session session = Session.getDefaultInstance(pro, null);

          Message msg = new MimeMessage(session);
          msg.setFrom(new InternetAddress(from));
          msg.setRecipient(Message.RecipientType.TO, InternetAddress.parse(to, false)[0]);
          msg.setSubject(subject);
          msg.setText(body);
          msg.setHeader("X-Mailer", "LOTONtechEmail");
          msg.setSentDate(new Date());

          Transport transport = session.getTransport("smtp");
          System.out.println("connecting...");
          transport.connect(SMTPSERVER, ACCOUNT, PWD);
          System.out.println("Sending message");
          transport.sendMessage(msg, msg.getAllRecipients());
          transport.close();
          }

          public static void main(String[] args) {
          TestMail test = new TestMail();
          try {
          test.sendMail(MAILADDR, MAILADDR, "test", "我的一個測試");
          } catch (AddressException e) {
          e.printStackTrace();
          } catch (MessagingException e) {
          e.printStackTrace();
          }
          }
          }

          posted @ 2006-09-15 10:30 小小~咖啡豆 閱讀(299) | 評論 (1)編輯 收藏
          主站蜘蛛池模板: 石首市| 普兰店市| 奉贤区| 钦州市| 井冈山市| 陵川县| 通山县| 富阳市| 罗平县| 容城县| 大连市| 江油市| 田林县| 伊宁县| 松溪县| 都昌县| 那坡县| 栾川县| 稻城县| 乐业县| 长垣县| 安徽省| 东海县| 米泉市| 乃东县| 上犹县| 贵南县| 冷水江市| 衡阳县| 高清| 长兴县| 海晏县| 保康县| 榆社县| 寿光市| 大英县| 南岸区| 青龙| 科技| 奉贤区| 沁源县|