PariScamper的java天空

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            14 Posts :: 0 Stories :: 7 Comments :: 0 Trackbacks

          2007年10月12日 #

          以下文章在我配置vsftpd時有幫助,特轉載:

          關于“vsftpd 部分本地用戶不能登錄,部分可以”的問題,我重新做了一些實驗,我把這個問題結合實驗的結果再重新描述一下,請各位高人,幫忙看看可能的原因。 謝謝了!

          系統中原來就有的本地帳號都不能登錄,我的/etc/vsftpd/vsftpd.conf文件的配置如下:
          local_enable=YES
          write_enable=YES
          chroot_local_user=YES
          pam_service_name=vsftpd
          /etc/pam.d/vsftpd存在且正常。

          登錄時錯誤信息都是一樣的:
          500 OOPS: cannot change directory:/home/xxxx
          Login failed.
          421 Service not available, remote server has closed connection

          他們的home目錄都是/home/xxxx。/home和/home/xxxx的權限都是755。
          以上這些帳號都不能ftp登錄,這些都是平常經常使用的,可以用shell登錄的。

          我新創建了一個usr1帳號,
          # useradd -G test -d /tmp/usr1 usr1
          能ftp登錄,他的home為/tmp/usr1,在/分區上。而/home我是mount到/dev/hda9上的。
          #mount
          /dev/hdb1 on / type ext3 (rw)
          /dev/hda9 on /home type ext2 (rw)

          所以,我猜想:是否是由于/home分區的原因,而造成“主目錄在/home分區的帳號”都不能登錄呢?

          為了驗證以上設想,我試著再創建了一個帳號,
          useradd -G test -d /home/usr3 usr3
          /home, /home/usr3 的權限都是755。

          usr3 ftp登錄失敗。
          500 OOPS: cannot change directory:/home/usr3
          Login failed.
          421 Service not available, remote server has closed connection

          至此,我覺得可以確定是由于/home分區的原因,而造成“主目錄在/home分區的帳號”都不能登錄。
          參考文章:
          -----------------------------------------------------------------------------------------
          I finished my second upgrade to Fedora Core 4. Not everything is ironed out yet with the build of course. But one thing is for sure a lot has happened to the RedHat I knew before.

          I must say of all the changes, for me the nicest addition is the new SELinux extensions. For deep background on the reasons for and theory of SELinux read, The Inevitability of Failure: The Flawed Assumption of Security in Modern Computing Environments

          The more I work with SELinux the more I realize I need to know about it, and how exactly it does all its stuff. It certainly changes things relating to users, directories and access. As I am starting to learn it, I'm sure I'm doing things the hard-way. :)

          The major difference, so far for me, in Red Hat's SELinux is the way ftp is handled. vsftpd is still the server which is great. However, it seems to be designed to run as a daemon rather than invoked via xinet.d. If you grab a working copy of the xinet.d file for vsftpd you can invoke it via xinet.d wrapper. I did my first server upgrade in this manner. The current one I am trying as a daemon. I certainly think I will miss some of the features that the xinet.d wrapper brings, and may yet return to it.

          Of all the issues I saw most notable is if you want to enable chroot directory's outside of the normal /home/xxx vsftpd. These will fail with a

              500 OOPS: cannot change directory: /mnt/xxxxx

          I was able to use ftp if I logged in with an account with a directory in /home, but once I set a user account to have a home drive outside of /home (in this case on a mounted secondary disk) vsftpd barfs the above.


          I found information at the NSA that indicates you can disable SELinux protection of the ftp daemon.

              setsebool -P ftpd_disable_trans 1

          This seems a bit drastic. It certainly works for now though.

          I think ultimately the issue resides with policies, but as SELinux policies are new to me, it will take time before it all gets sorted out. As I spend time with the new SELinux extensions in Fedora Core 4 I will keep you updated on my thoughts and configuration lessons.


          ---------------------------------------------------------------------------------------

          解決辦法:
          --------------------------------------------------------------------------------------
           # setsebool ftpd_disable_trans 1
            # service vsftpd restart
          我用的是FC4,按照你上一帖子里的方法試了,馬上就解決了。所以,可以確定原因就在SELinux。
          ------------------------------------------------------------------------------------

          posted @ 2008-02-27 22:45 PariScamper 閱讀(448) | 評論 (0)編輯 收藏

          1          什么是 Clone ,容易實現嗎?

          簡單地說, Clone 就是對于給定的一個對象實例 o ,得到另一個對象實例 o’ o o’

          型相同( o.getClass() == o’.getClass() ),內容相同(對于 o/o’ 中的字段 f ,如果 f 是基本數據類型,則 o.f == o’.f ;如果 f 是對象引用,則 o.f == o’.f o.f 指向的對象與 o’.f 指向的對象的內容相同)。通常稱 o’ o 的克隆或副本。

                 直觀上看,似乎很容易為一個類加上 clone 方法:

          class A {

                 private Type1 field1;

              private Type2 field2;

               …..

              public Object clone() {

                        A a = new A();

                  a.field1 = a.getField1();

                  a.field2 = a.getField2();

                  ……

                  return a;

              }

          }

           

          然而,稍加推敲,就會發現這樣的實現方法有兩個問題:

          1.         要想某個類有 clone 功能,必須單獨為其實現 clone() 函數,函數實現代碼與該類定義密切相關。

          2.         即使基類 A 已有 clone() 函數,其子類 ExtendA 若要具備 clone 功能,則必須 override 其基類 A clone() 函數。否則,對類型為 ExtendA 的對象 ea clone() 方法的調用,會執行于類 A 中定義的 clone() 方法而返回一個類型為 A 的對象,它顯然不是 ea 的克隆。

          2          Java clone 的支持

          萬類之初的 Object 類有 clone() 方法:

          protected native Object clone() throws CloneNotSupportedException;

          該方法是 protected 的,顯然是留待被子類 override 的。該方法又是 native 的,必然做了

          與具體平臺相關的底層工作。

          事實上,類 Object clone() 方法首先會檢查 this.getClass() 是否實現了 Cloneable 接口。

          Cloneable 只是一個標志接口而已,用來標志該類是否有克隆功能。

          public interface Cloneable {

          }

                 如果 this.getClass() 沒有實現 Cloneable 接口, clone() 就會拋 CloneNotSupportedException 返回。否則就會創建一個類型為 this.getClass() 的對象 other ,并將 this field 的值賦值給 other 的對應 field ,然后返回 other 。

                 如此一來,我們要定義一個具有 Clone 功能的類就相當方便:

          1.         在類的聲明中加入“ implements Cloneable ”,標志該類有克隆功能;

          2.         Override Object clone() 方法,在該方法中調用 super.clone()

          class CloneableClass implements Cloneable {

                 ……

          public Object clone() {

                 try {

                        return super.clone(); // 直接讓 Object.clone() 為我們代勞一切

              } catch (CloneNotSupportedException e) {

                        throw new InternalError();

                 }

          }

          }

           

          3          Shallow Clone Deep Clone

          3.1     Shallow Deep 從何而來

          一個具有克隆功能的類,如果有可變( Mutable )類類型的字段 field ,如何為其克隆(副

          本)對象 o’ 中的 field 賦值?

                 方法一、如 Object clone() 方法所實現:設原始對象為 o ,其克隆對象是 o’ ,執行 o’.field = o.field 。這樣, o’.field o.field 指向同一個可變對象 m o o’ 可能會相互影響(一個對象的狀態可能會隨著另一個對象的狀態的改變而改變)。這樣的 Clone 稱為 Shallow Clone 。這也是 Object clone() 方法的實現方式。

                 方法二、將 o.field 指向的可變對象 m 克隆,得到 m’ ,將 m’ 的引用賦值給 o’.field 。這樣 o’ o 內容相同,且相互之間無影響(一個對象狀態的改變不會影響另一個對象的狀態)。這樣的 Clone 稱為 Deep Clone

                 Java Collection 類庫中具體數據結構類( ArrayList/LinkedList HashSet/TreeSet , HashMap/TreeMap 等)都具有克隆功能,且都是 Shallow Clone ,這樣設計是合理的,因為它們不知道存放其中的每個數據對象是否也有克隆功能。 System.arrayCopy() 的實現采用的也是 Shallow Clone

                 Deep Clone 對于實現不可變( Immutable )類很有幫助。設一個類包含可變類 M 類型的 field ,如何將其設計為不可變類呢?先為 M 實現 Deep Clone 功能,然后這樣設計類 ImmutableClass

          class ImmutableClass {

                 MutableClass m;

          ImmutableClass(MutableClass m) {

                 this.m = m.clone(); // 將傳入的 m clone 賦值給內部 m

          }

          public MutableClass getM() {

              return this.m.clone(); // 將內部 m clone 返回給外部

          }

          }

           

                

          3.2     如何實現 Deep Clone

          檢查類有無可變類類型的字段。如果無,返回 super.clone() 即可;

          如果有,確保包含的可變類本身都實現了 Deep Clone ;

          Object o = super.clone(); // 先執行淺克隆,確保類型正確和基本類型及非可變類類型字段內容正確

          對于每一個可變類類型的字段 field

                 o.field = this.getField().clone();

          返回 o

          posted @ 2007-12-12 14:49 PariScamper 閱讀(757) | 評論 (0)編輯 收藏

          什么要用日志(Log?
          這個……就不必說了吧。

          為什么不用System.out.println()?
          功能太弱;不易于控制。如果暫時不想輸出了怎么辦?如果想輸出到文件怎么辦?如果想部分輸出怎么辦?……

          為什么同時使用commons-loggingLog4j?為什么不僅使用其中之一?
          Commons-loggin的目的是為“所有的Java日志實現”提供一個統一的接口,它自身的日志功能平常弱(只有一個簡單的SimpleLog?),所以一般不會單獨使用它。

          Log4j的功能非常全面強大,是目前的首選。我發現幾乎所有的Java開源項目都會用到Log4j,但我同時發現,所有用到Log4j的項目一般也同時會用到commons-loggin。我想,大家都不希望自己的項目與Log4j綁定的太緊密吧。另外一個我能想到的“同時使用commons-loggingLog4j”的原因是,簡化使用和配置。

                 強調一點,“同時使用commons-loggingLog4j”,與“單獨使用Log4j”相比,并不會帶來更大的學習、配置和維護成本,反而更加簡化了我們的工作。我想這也是為什么“所有用到Log4j的項目一般也同時會用到commons-loggin”的原因之一吧。

          Commons-logging能幫我們做什么?
          l         提供一個統一的日志接口,簡單了操作,同時避免項目與某個日志實現系統緊密a耦合
          l         很貼心的幫我們自動選擇適當的日志實現系統(這一點非常好!)
          l         它甚至不需要配置

          這里看一下它怎么“‘很貼心的’幫我們‘自動選擇’‘適當的’日志實現系統”:
          1)        首先在classpath下尋找自己的配置文件commons-logging.properties,如果找到,則使用其中定義的Log實現類;
          2)        如果找不到commons-logging.properties文件,則在查找是否已定義系統環境變量org.apache.commons.logging.Log,找到則使用其定義的Log實現類;
          3)        否則,查看classpath中是否有Log4j的包,如果發現,則自動使用Log4j作為日志實現類;
          4)        否則,使用JDK自身的日志實現類(JDK1.4以后才有日志實現類);
          5)        否則,使用commons-logging自己提供的一個簡單的日志實現類SimpleLog
          (以上順序不保證完全準確,請參考官方文檔)

          可見,commons-logging總是能找到一個日志實現類,并且盡可能找到一個“最合適”的日志實現類。我說它“很貼心”實際上是因為:1、可以不需要配置文件;2、自動判斷有沒有Log4j包,有則自動使用之;3、最悲觀的情況下也總能保證提供一個日志實現(SimpleLog)。 
                 可以看到,commons-logging對編程者和Log4j都非常友好。

                 為了簡化配置commons-logging,一般不使用commons-logging的配置文件,也不設置與commons-logging相關的系統環境變量,而只需將Log4jJar包放置到classpash中就可以了。這樣就很簡單地完成了commons-loggingLog4j的融合。如果不想用Log4j了怎么辦?只需將classpath中的Log4jJar包刪除即可。

          就這么簡單!

          代碼應該怎么寫?

          我們在需要輸出日志信息的“每一人”類中做如下的三個工作:
          1、導入所有需的commongs-logging類:
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;

          如果愿意簡化的話,還可以兩行合為一行:
          import org.apache.commons.logging.*;  

          2、在自己的類中定義一個org.apache.commons.logging.Log類的私有靜態類成員:
          private static Log log = LogFactory.getLog(YouClassName.class);

          注意這里定義的是static成員,以避免產生多個實例。

          LogFactory.getLog()方法的參數使用的是當前類的class,這是目前被普通認為的最好的方式。為什么不寫作LogFactory.getLog(this.getClass())?因為static類成員訪問不到this指針!

          3、使用org.apache.commons.logging.Log類的成員方法輸出日志信息:
          log.debug("111");
          log.info("222");
          log.warn("333");
          log.error("444");
          log.fatal("555");

          這里的log,就是上面第二步中定義的類成員變量,其類型是org.apache.commons.logging.Log,通過該類的成員方法,我們就可以將不同性質的日志信息輸出到目的地(目的地是哪里?視配置可定,可能是stdout,也可能是文件,還可能是發送到郵件,甚至發送短信到手機……詳見下文對log4j.properties的介紹):
          l         debug()   輸出“調試”級別的日志信息;
          l         info()      輸出“信息”級別的日志信息;
          l         warn()    輸出“警告”級別的日志信息;
          l         error()     輸出“錯誤”級別的日志信息;
          l         fatal()      輸出“致命錯誤”級別的日志信息;

          根據不同的性質,日志信息通常被分成不同的級別,從低到高依次是:“調試(DEBUG)”“信息(INFO)”“警告(WARN)”“錯誤(ERROR)”“致命錯誤(FATAL)”。為什么要把日志信息分成不同的級別呢?這實際上是方便我們更好的控制它。比如,通過Log4j的配置文件,我們可以設置“輸出‘調試’及以上級別的日志信息”(即“調試”“信息”“警告”“錯誤”“致命錯誤”),這對項目開發人員可能是有用的;我們還可以設置“輸出“警告”及以上級別的日志信息”(即“警告”“錯誤”“致命錯誤”),這對項目最終用戶可能是有用的。 
                 僅從字面上理解,也可以大致得出結論:最常用的應該是debug()info();而warn()error()、fatal()僅在相應事件發生后才使用。  

          從上面三個步驟可以看出,使用commons-logging的日志接口非常的簡單,不需要記憶太多東西:僅僅用到了兩個類Log, LogFactory,并且兩個類的方法都非常少(后者只用到一個方法,前者經常用到的也只是上面第三步中列出的幾個),同時參數又非常簡單。

          上面所介紹的方法是目前被普通應用的,可以說是被標準化了的方法,幾乎所有的人都是這么用。如果不信,或想確認一下,就去下載幾個知名的Java開源項目源代碼看一下吧。  

          下面給出一個完整的Java類的代碼: 
          package liigo.testlog; 
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory; 

          public class TestLog
              private static Log log = LogFactory.getLog(TestLog.class); 
              public void test()    
                  log.debug("111"); 
                  log.info("222"); 
                  log.warn("333"); 
                  log.error("444"); 
                  log.fatal("555"); 
               

              public static void main(String[] args)    
                  TestLog testLog = new TestLog(); 
                  testLog.test(); 
              }
           

          只要保證commons-loggingjar包在classpath中,上述代碼肯定可以很順利的編譯通過。那它的執行結果是怎么樣的呢?恐怕會有很大的不同,請繼續往下看。  

          Log4j在哪里呢?它發揮作用了嗎?

          應該注意到,我們上面給出的源代碼,完全沒有涉及到Log4j——這正是我們所希望的,這也正是commons-logging所要達到的目標之一。

          可是,怎么才能讓Log4j發揮它的作用呢?答案很簡單,只需滿足“classpath中有Log4jjar包”。前面已經說過了,commons-logging會自動發現并應用Log4j。所以只要它存在,它就發揮作用。(它不存在呢?自然就不發揮作用,commons-logging會另行選擇其它的日志實現類。)

          注意:配置文件log4j.propertiesLog4j來說是必須的。如果classpath中沒有該配置文件,或者配置不對,將會引發運行時異常。

                 這樣,要正確地應用Log4j輸出日志信息,log4j.properties的作用就很重要了。好在該文件有通用的模板,復制一份(稍加修改)就可以使用。幾乎每一個Java項目目錄內都會有一個log4j.properties文件,可下載幾個Java開源項目源代碼查看。本文最后也附一個模板性質的log4j.properties文件,直接復制過去就可以用,或者根據自己的需要稍加修改。后文將會log4j.properties文件適當作一些介紹。

          關于Log4j比較全面的配置

          LOG4J的配置之簡單使它遍及于越來越多的應用中了:Log4J配置文件實現了輸出到控制臺、文件、

          回滾文件、發送日志郵件、輸出到數據庫日志表、自定義標簽等全套功能。擇其一二使用就夠用了

          log4j.rootLogger=DEBUG,CONSOLE,A1,im
          log4j.addivity.org.apache=true 
           

          # 應用于控制臺
          log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
          log4j.appender.Threshold=DEBUG
          log4j.appender.CONSOLE.Target=System.out
          log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
          log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
          #log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n

          #應用于文件
          log4j.appender.FILE=org.apache.log4j.FileAppender
          log4j.appender.FILE.File=file.log
          log4j.appender.FILE.Append=false
          log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
          log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
          # Use this layout for LogFactor 5 analysis


          # 應用于文件回滾
          log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
          log4j.appender.ROLLING_FILE.Threshold=ERROR
          log4j.appender.ROLLING_FILE.File=rolling.log
          log4j.appender.ROLLING_FILE.Append=true
          log4j.appender.ROLLING_FILE.MaxFileSize=10KB
          log4j.appender.ROLLING_FILE.MaxBackupIndex=1
          log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
          log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

          #應用于socket
          log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
          log4j.appender.SOCKET.RemoteHost=localhost
          log4j.appender.SOCKET.Port=5001
          log4j.appender.SOCKET.LocationInfo=true
          # Set up for Log Facter 5
          log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
          log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n


          # Log Factor 5 Appender
          log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
          log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

          # 發送日志給郵件
          log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
          log4j.appender.MAIL.Threshold=FATAL
          log4j.appender.MAIL.BufferSize=10
          log4j.appender.MAIL.From=web@www.wuset.com
          log4j.appender.MAIL.SMTPHost=www.wusetu.com
          log4j.appender.MAIL.Subject=Log4J Message
          log4j.appender.MAIL.To=web@www.wusetu.com
          log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
          log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


          # 用于數據庫
          log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
          log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
          log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
          log4j.appender.DATABASE.user=root
          log4j.appender.DATABASE.password=
          log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
          log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
          log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


          log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.A1.File=SampleMessages.log4j
          log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
          log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout

          #自定義Appender
          log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender

          log4j.appender.im.host = mail.cybercorlin.net
          log4j.appender.im.username = username
          log4j.appender.im.password = password
          log4j.appender.im.recipient = corlin@cybercorlin.net

          log4j.appender.im.layout=org.apache.log4j.PatternLayout
          log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1545873

          posted @ 2007-12-12 14:48 PariScamper 閱讀(2053) | 評論 (2)編輯 收藏

          就servlet規范本身,數據可以放在3個地方:request、session、servletContext.

          request:
          好處:用完就仍,不會導致資源占用的無限增長。
          弊處:每次要用都從數據庫中抓,多做操作,自然會對性能有一些影響。

          session:
          好處:不用每次都去數據庫抓,少做操作。
          弊處:每個客戶都有一個session,只能自己使用,不同session可能保存大量重復數據;
          可能耗費大量服務器內存;
          另外session構建在cookie和url重寫的基礎上,所以用session實現會話跟蹤,會用掉一點點服務器帶寬和客戶端保持聯絡,
          當然session越多,耗費的帶寬越多,理論上也會對性能造成影響。
          集群的session同步會是個問題。

          servletContext:
          好處:不用每次都去數據庫抓,少做操作。
          存儲的數據所有客戶都可以用。
          可減少重復在內存中存儲數據造成的開銷。
          弊處:很多時候相同的數據可能不多(相當于cache的命中率很低)。


          其實以上3中方法都有利有弊,各自的好處在某種條件下,也都會轉變為弊處。所以不妨綜合使用,相當于一個“第三方用法”(只講一下思路,否則太過繁瑣,涉及到的相關技術點請參考有關技術資料):

          request不說了,重點說說session和servletContext:

          --session的可控應用
          session的最大問題是資源回收,兩類回收方法:
          主動回收:瀏覽器被關閉,而為提交觸發清理動作的請求時,該方法失效,而且很常見。
          超時回收:設置session的setMaxInactiveInterval屬性或在web.xml中配置超時時間,然后交給jvm的垃圾處理器處理。
          不過不要報太大希望,jvm的垃圾收集器并不靈光。
          可以用另一種替代方法緩解該問題,比如限制session的數量,可以用HttpSessionListener實現,這樣可以緩解session帶來的吃內存問題,當然這種做法每次都需要判斷session數量,當session達到限定數量時還必須用其他方法處理了,這些細節繁瑣,而且要謹慎處理。

          --servletContext
          如果說session是一個“局部緩存”,那servletContext就是一個“全局緩存”了,不妨把它當作cache(這里不講究用詞的嚴謹性,僅為了更好說明問題)。cache的大小是當前應用可使用的最大內存。cache的最大問題是提高命中率,命中率高,內存占用少,效率高,命中率低,則內存占用多而且效率低。這種應用的技術實現比“session的可空應用”要簡單,適用于相同數據多的地方,這個要事先有所判斷,如果用不好則有弊無利。

          如果僅使用servlet規范給出的3種機制,任何一種都達不到好處兼收的效果,所以要發揮3種方法的好處、摒棄弊處,必須綜合運用,做一些技術框架的構建工作,而且有些地方還比較繁瑣(還好框架是可重用的)。
           

          有時候尋求或實現“平衡”(或者說盡取其利而摒其害),要付出很大代價,根據不同的情況,這些代價或是值得,或是不值得。也可以“兩害相權取其輕”,或許是最便捷的方法。

          posted @ 2007-11-19 13:18 PariScamper 閱讀(784) | 評論 (0)編輯 收藏

          注意如果該字段在Oracle中設定非空性為YES,則即使是插入String a=""或者String a=new String()也是相對于空值。

          posted @ 2007-10-23 15:29 PariScamper 閱讀(7677) | 評論 (3)編輯 收藏

          六種異常處理的陋習

          你覺得自己是一個Java專家嗎?是否肯定自己已經全面掌握了Java的異常處理機制?在下面這段代碼中,你能夠迅速找出異常處理的六個問題嗎?

          1 OutputStreamWriter out = ...
          2 java.sql.Connection conn = ...
          3 try { // ⑸
          4  Statement stat = conn.createStatement();
          5  ResultSet rs = stat.executeQuery(
          6   "select uid, name from user");
          7  while (rs.next())
          8  {
          9   out.println("ID:" + rs.getString("uid") // ⑹
          10    ",姓名:" + rs.getString("name"));
          11  }
          12  conn.close(); // ⑶
          13  out.close();
          14 }
          15 catch(Exception ex) // ⑵
          16 {
          17  ex.printStackTrace(); //⑴,⑷
          18 }


            作為一個Java程序員,你至少應該能夠找出兩個問題。但是,如果你不能找出全部六個問題,請繼續閱讀本文。

            本文討論的不是Java異常處理的一般性原則,因為這些原則已經被大多數人熟知。我們要做的是分析各種可稱為“反例”(anti-pattern)的違背優秀編碼規范的常見壞習慣,幫助讀者熟悉這些典型的反面例子,從而能夠在實際工作中敏銳地察覺和避免這些問題。

            反例之一:丟棄異常

            代碼:15行-18行。

            這段代碼捕獲了異常卻不作任何處理,可以算得上Java編程中的殺手。從問題出現的頻繁程度和禍害程度來看,它也許可以和C/C++程序的一個惡名遠播的問題相提并論??不檢查緩沖區是否已滿。如果你看到了這種丟棄(而不是拋出)異常的情況,可以百分之九十九地肯定代碼存在問題(在極少數情況下,這段代碼有存在的理由,但最好加上完整的注釋,以免引起別人誤解)。

            這段代碼的錯誤在于,異常(幾乎)總是意味著某些事情不對勁了,或者說至少發生了某些不尋常的事情,我們不應該對程序發出的求救信號保持沉默和無動于衷。調用一下printStackTrace算不上“處理異常”。不錯,調用printStackTrace對調試程序有幫助,但程序調試階段結束之后,printStackTrace就不應再在異常處理模塊中擔負主要責任了。

            丟棄異常的情形非常普遍。打開JDK的ThreadDeath類的文檔,可以看到下面這段說明:“特別地,雖然出現ThreadDeath是一種‘正常的情形’,但ThreadDeath類是Error而不是Exception的子類,因為許多應用會捕獲所有的Exception然后丟棄它不再理睬。”這段話的意思是,雖然ThreadDeath代表的是一種普通的問題,但鑒于許多應用會試圖捕獲所有異常然后不予以適當的處理,所以JDK把ThreadDeath定義成了Error的子類,因為Error類代表的是一般的應用不應該去捕獲的嚴重問題??梢姡瑏G棄異常這一壞習慣是如此常見,它甚至已經影響到了Java本身的設計。

            那么,應該怎樣改正呢?主要有四個選擇:

            1、處理異常。針對該異常采取一些行動,例如修正問題、提醒某個人或進行其他一些處理,要根據具體的情形確定應該采取的動作。再次說明,調用printStackTrace算不上已經“處理好了異常”。

            2、重新拋出異常。處理異常的代碼在分析異常之后,認為自己不能處理它,重新拋出異常也不失為一種選擇。

            3、把該異常轉換成另一種異常。大多數情況下,這是指把一個低級的異常轉換成應用級的異常(其含義更容易被用戶了解的異常)。

            4、不要捕獲異常。

            結論一:既然捕獲了異常,就要對它進行適當的處理。不要捕獲異常之后又把它丟棄,不予理睬。

            反例之二:不指定具體的異常

            代碼:15行。

            許多時候人們會被這樣一種“美妙的”想法吸引:用一個catch語句捕獲所有的異常。最常見的情形就是使用catch(Exception ex)語句。但實際上,在絕大多數情況下,這種做法不值得提倡。為什么呢?

            要理解其原因,我們必須回顧一下catch語句的用途。catch語句表示我們預期會出現某種異常,而且希望能夠處理該異常。異常類的作用就是告訴Java編譯器我們想要處理的是哪一種異常。由于絕大多數異常都直接或間接從java.lang.Exception派生,catch(Exception ex)就相當于說我們想要處理幾乎所有的異常。

            再來看看前面的代碼例子。我們真正想要捕獲的異常是什么呢?最明顯的一個是SQLException,這是JDBC操作中常見的異常。另一個可能的異常是IOException,因為它要操作OutputStreamWriter。顯然,在同一個catch塊中處理這兩種截然不同的異常是不合適的。如果用兩個catch塊分別捕獲SQLException和IOException就要好多了。這就是說,catch語句應當盡量指定具體的異常類型,而不應該指定涵蓋范圍太廣的Exception類。

            另一方面,除了這兩個特定的異常,還有其他許多異常也可能出現。例如,如果由于某種原因,executeQuery返回了null,該怎么辦?答案是讓它們繼續拋出,即不必捕獲也不必處理。實際上,我們不能也不應該去捕獲可能出現的所有異常,程序的其他地方還有捕獲異常的機會??直至最后由JVM處理。

            結論二:在catch語句中盡可能指定具體的異常類型,必要時使用多個catch。不要試圖處理所有可能出現的異常。

            反例之三:占用資源不釋放

            代碼:3行-14行。

            異常改變了程序正常的執行流程。這個道理雖然簡單,卻常常被人們忽視。如果程序用到了文件、Socket、JDBC連接之類的資源,即使遇到了異常,也要正確釋放占用的資源。為此,Java提供了一個簡化這類操作的關鍵詞finally。

            finally是樣好東西:不管是否出現了異常,Finally保證在try/catch/finally塊結束之前,執行清理任務的代碼總是有機會執行。遺憾的是有些人卻不習慣使用finally。

            當然,編寫finally塊應當多加小心,特別是要注意在finally塊之內拋出的異常??這是執行清理任務的最后機會,盡量不要再有難以處理的錯誤。

            結論三:保證所有資源都被正確釋放。充分運用finally關鍵詞。

          反例之四:不說明異常的詳細信息

            代碼:3行-18行。

            仔細觀察這段代碼:如果循環內部出現了異常,會發生什么事情?我們可以得到足夠的信息判斷循環內部出錯的原因嗎?不能。我們只能知道當前正在處理的類發生了某種錯誤,但卻不能獲得任何信息判斷導致當前錯誤的原因。

            printStackTrace的堆棧跟蹤功能顯示出程序運行到當前類的執行流程,但只提供了一些最基本的信息,未能說明實際導致錯誤的原因,同時也不易解讀。

            因此,在出現異常時,最好能夠提供一些文字信息,例如當前正在執行的類、方法和其他狀態信息,包括以一種更適合閱讀的方式整理和組織printStackTrace提供的信息。

            結論四:在異常處理模塊中提供適量的錯誤原因信息,組織錯誤信息使其易于理解和閱讀。

            反例之五:過于龐大的try塊

            代碼:3行-14行。

            經常可以看到有人把大量的代碼放入單個try塊,實際上這不是好習慣。這種現象之所以常見,原因就在于有些人圖省事,不愿花時間分析一大塊代碼中哪幾行代碼會拋出異常、異常的具體類型是什么。把大量的語句裝入單個巨大的try塊就象是出門旅游時把所有日常用品塞入一個大箱子,雖然東西是帶上了,但要找出來可不容易。

            一些新手常常把大量的代碼放入單個try塊,然后再在catch語句中聲明Exception,而不是分離各個可能出現異常的段落并分別捕獲其異常。這種做法為分析程序拋出異常的原因帶來了困難,因為一大段代碼中有太多的地方可能拋出Exception。

            結論五:盡量減小try塊的體積。

            反例之六:輸出數據不完整

            代碼:7行-11行。

            不完整的數據是Java程序的隱形殺手。仔細觀察這段代碼,考慮一下如果循環的中間拋出了異常,會發生什么事情。循環的執行當然是要被打斷的,其次,catch塊會執行??就這些,再也沒有其他動作了。已經輸出的數據怎么辦?使用這些數據的人或設備將收到一份不完整的(因而也是錯誤的)數據,卻得不到任何有關這份數據是否完整的提示。對于有些系統來說,數據不完整可能比系統停止運行帶來更大的損失。

            較為理想的處置辦法是向輸出設備寫一些信息,聲明數據的不完整性;另一種可能有效的辦法是,先緩沖要輸出的數據,準備好全部數據之后再一次性輸出。

            結論六:全面考慮可能出現的異常以及這些異常對執行流程的影響。

            改寫后的代碼

            根據上面的討論,下面給出改寫后的代碼。也許有人會說它稍微有點?嗦,但是它有了比較完備的異常處理機制。

          OutputStreamWriter out = ...
          java.sql.Connection conn = ...
          try {
           Statement stat = conn.createStatement();
           ResultSet rs = stat.executeQuery(
            "select uid, name from user");
           while (rs.next())
           {
            out.println("ID:" + rs.getString("uid") + ",姓名: " + rs.getString("name"));
           }
          }
          catch(SQLException sqlex)
          {
           out.println("警告:數據不完整");
           throw new ApplicationException("讀取數據時出現SQL錯誤", sqlex);
          }
          catch(IOException ioex)
          {
           throw new ApplicationException("寫入數據時出現IO錯誤", ioex);
          }
          finally
          {
           if (conn != null) {
            try {
             conn.close();
            }
            catch(SQLException sqlex2)
            {
             System.err(this.getClass().getName() + ".mymethod - 不能關閉數據庫連接: " + sqlex2.toString());
            }
           }

           if (out != null) {
            try {
             out.close();
            }
            catch(IOException ioex2)
            {
             System.err(this.getClass().getName() + ".mymethod - 不能關閉輸出文件" + ioex2.toString());
            }
           }
          }

            本文的結論不是放之四海皆準的教條,有時常識和經驗才是最好的老師。如果你對自己的做法沒有百分之百的信心,務必加上詳細、全面的注釋。

            另一方面,不要笑話這些錯誤,不妨問問你自己是否真地徹底擺脫了這些壞習慣。即使最有經驗的程序員偶爾也會誤入歧途,原因很簡單,因為它們確確實實帶來了“方便”。所有這些反例都可以看作Java編程世界的惡魔,它們美麗動人,無孔不入,時刻誘惑著你。也許有人會認為這些都屬于雞皮蒜毛的小事,不足掛齒,但請記住:勿以惡小而為之,勿以善小而不為。





          ------------------------------------------------------------------下面是一些java異常集-------------------------------------------------------------------------------------------


          算術異常類:ArithmeticExecption

          空指針異常類:NullPointerException

          類型強制轉換異常:ClassCastException

          數組負下標異常:NegativeArrayException

          數組下標越界異常:ArrayIndexOutOfBoundsException

          違背安全原則異常:SecturityException

          文件已結束異常:EOFException

          文件未找到異常:FileNotFoundException

          字符串轉換為數字異常:NumberFormatException


          操作數據庫異常:SQLException


          輸入輸出異常:IOException


          方法未找到異常:NoSuchMethodException

          java.lang.AbstractMethodError

          抽象方法錯誤。當應用試圖調用抽象方法時拋出。

          java.lang.AssertionError

          斷言錯。用來指示一個斷言失敗的情況。

          java.lang.ClassCircularityError

          類循環依賴錯誤。在初始化一個類時,若檢測到類之間循環依賴則拋出該異常。

          java.lang.ClassFormatError

          類格式錯誤。當Java虛擬機試圖從一個文件中讀取Java類,而檢測到該文件的內容不符合類的有效格式時拋出。

          java.lang.Error

          錯誤。是所有錯誤的基類,用于標識嚴重的程序運行問題。這些問題通常描述一些不應被應用程序捕獲的反常情況。

          java.lang.ExceptionInInitializerError

          初始化程序錯誤。當執行一個類的靜態初始化程序的過程中,發生了異常時拋出。靜態初始化程序是指直接包含于類中的static語句段。

          java.lang.IllegalAccessError

          違法訪問錯誤。當一個應用試圖訪問、修改某個類的域(Field)或者調用其方法,但是又違反域或方法的可見性聲明,則拋出該異常。

          java.lang.IncompatibleClassChangeError

          不兼容的類變化錯誤。當正在執行的方法所依賴的類定義發生了不兼容的改變時,拋出該異常。一般在修改了應用中的某些類的聲明定義而沒有對整個應用重新編譯而直接運行的情況下,容易引發該錯誤。

          java.lang.InstantiationError

          實例化錯誤。當一個應用試圖通過Java的new操作符構造一個抽象類或者接口時拋出該異常.

          java.lang.InternalError

          內部錯誤。用于指示Java虛擬機發生了內部錯誤。

          java.lang.LinkageError

          鏈接錯誤。該錯誤及其所有子類指示某個類依賴于另外一些類,在該類編譯之后,被依賴的類改變了其類定義而沒有重新編譯所有的類,進而引發錯誤的情況。

          java.lang.NoClassDefFoundError

          未找到類定義錯誤。當Java虛擬機或者類裝載器試圖實例化某個類,而找不到該類的定義時拋出該錯誤。

          java.lang.NoSuchFieldError

          域不存在錯誤。當應用試圖訪問或者修改某類的某個域,而該類的定義中沒有該域的定義時拋出該錯誤。

          java.lang.NoSuchMethodError

          方法不存在錯誤。當應用試圖調用某類的某個方法,而該類的定義中沒有該方法的定義時拋出該錯誤。

          java.lang.OutOfMemoryError

          內存不足錯誤。當可用內存不足以讓Java虛擬機分配給一個對象時拋出該錯誤。

          java.lang.StackOverflowError

          堆棧溢出錯誤。當一個應用遞歸調用的層次太深而導致堆棧溢出時拋出該錯誤。

          java.lang.ThreadDeath

          線程結束。當調用Thread類的stop方法時拋出該錯誤,用于指示線程結束。

          java.lang.UnknownError

          未知錯誤。用于指示Java虛擬機發生了未知嚴重錯誤的情況。

          java.lang.UnsatisfiedLinkError

          未滿足的鏈接錯誤。當Java虛擬機未找到某個類的聲明為native方法的本機語言定義時拋出。

          java.lang.UnsupportedClassVersionError

          不支持的類版本錯誤。當Java虛擬機試圖從讀取某個類文件,但是發現該文件的主、次版本號不被當前Java虛擬機支持的時候,拋出該錯誤。

          java.lang.VerifyError

          驗證錯誤。當驗證器檢測到某個類文件中存在內部不兼容或者安全問題時拋出該錯誤。

          java.lang.VirtualMachineError

          虛擬機錯誤。用于指示虛擬機被破壞或者繼續執行操作所需的資源不足的情況。


          java.lang.ArithmeticException

          算術條件異常。譬如:整數除零等。

          java.lang.ArrayIndexOutOfBoundsException

          數組索引越界異常。當對數組的索引值為負數或大于等于數組大小時拋出。

          java.lang.ArrayStoreException

          數組存儲異常。當向數組中存放非數組聲明類型對象時拋出。

          java.lang.ClassCastException

          類造型異常。假設有類A和B(A不是B的父類或子類),O是A的實例,那么當強制將O構造為類B的實例時拋出該異常。該異常經常被稱為強制類型轉換異常。

          java.lang.ClassNotFoundException

          找不到類異常。當應用試圖根據字符串形式的類名構造類,而在遍歷CLASSPAH之后找不到對應名稱的class文件時,拋出該異常。

          java.lang.CloneNotSupportedException

          不支持克隆異常。當沒有實現Cloneable接口或者不支持克隆方法時,調用其clone()方法則拋出該異常。

          java.lang.EnumConstantNotPresentException

          枚舉常量不存在異常。當應用試圖通過名稱和枚舉類型訪問一個枚舉對象,但該枚舉對象并不包含常量時,拋出該異常。

          java.lang.Exception

          根異常。用以描述應用程序希望捕獲的情況。

          java.lang.IllegalAccessException

          違法的訪問異常。當應用試圖通過反射方式創建某個類的實例、訪問該類屬性、調用該類方法,而當時又無法訪問類的、屬性的、方法的或構造方法的定義時拋出該異常。

          java.lang.IllegalMonitorStateException

          違法的監控狀態異常。當某個線程試圖等待一個自己并不擁有的對象(O)的監控器或者通知其他線程等待該對象(O)的監控器時,拋出該異常。

          java.lang.IllegalStateException

          違法的狀態異常。當在Java環境和應用尚未處于某個方法的合法調用狀態,而調用了該方法時,拋出該異常。

          java.lang.IllegalThreadStateException

          違法的線程狀態異常。當縣城尚未處于某個方法的合法調用狀態,而調用了該方法時,拋出異常。

          java.lang.IndexOutOfBoundsException

          索引越界異常。當訪問某個序列的索引值小于0或大于等于序列大小時,拋出該異常。

          java.lang.InstantiationException

          實例化異常。當試圖通過newInstance()方法創建某個類的實例,而該類是一個抽象類或接口時,拋出該異常。

          java.lang.InterruptedException

          被中止異常。當某個線程處于長時間的等待、休眠或其他暫停狀態,而此時其他的線程通過Thread的interrupt方法終止該線程時拋出該異常。

          java.lang.NegativeArraySizeException

          數組大小為負值異常。當使用負數大小值創建數組時拋出該異常。

          java.lang.NoSuchFieldException

          屬性不存在異常。當訪問某個類的不存在的屬性時拋出該異常。

          java.lang.NoSuchMethodException

          方法不存在異常。當訪問某個類的不存在的方法時拋出該異常。

          java.lang.NullPointerException

          空指針異常。當應用試圖在要求使用對象的地方使用了null時,拋出該異常。譬如:調用null對象的實例方法、訪問null對象的屬性、計算null對象的長度、使用throw語句拋出null等等。

          java.lang.NumberFormatException

          數字格式異常。當試圖將一個String轉換為指定的數字類型,而該字符串確不滿足數字類型要求的格式時,拋出該異常。

          java.lang.RuntimeException

          運行時異常。是所有Java虛擬機正常操作期間可以被拋出的異常的父類。

          java.lang.SecurityException

          安全異常。由安全管理器拋出,用于指示違反安全情況的異常。

          java.lang.StringIndexOutOfBoundsException

          字符串索引越界異常。當使用索引值訪問某個字符串中的字符,而該索引值小于0或大于等于序列大小時,拋出該異常。

          java.lang.TypeNotPresentException

          類型不存在異常。當應用試圖以某個類型名稱的字符串表達方式訪問該類型,但是根據給定的名稱又找不到該類型是拋出該異常。該異常與ClassNotFoundException的區別在于該異常是unchecked(不被檢查)異常,而ClassNotFoundException是checked(被檢查)異常。

          java.lang.UnsupportedOperationException

          不支持的方法異常。指明請求的方法不被支持情況的異常。

          異常
          javax.servlet.jsp.JspException: Cannot retrieve mapping for action /Login (/Login是你的action名字)  

          可能原因
          action沒有再struts-config.xml 中定義,或沒有找到匹配的action,例如在JSP文件中使用 <html:form action="Login.do".將表單提交給Login.do處理,如果出現上述異常,請查看struts-config.xml中的定義部分,有時可能是打錯了字符或者是某些不符合規則,可以使用strutsconsole工具來檢查。
          -----------------------------------------------------------------------------------------------------------------
          異常
          org.apache.jasper.JasperException: Cannot retrieve definition for form bean null

          可能原因     
                
          這個異常是因為Struts根據struts-config.xml中的mapping沒有找到action期望的form bean。大部分的情況可能是因為在form-bean中設置的name屬性和action中設置的name屬性不匹配所致。換句話說,action和form都應該各自有一個name屬性,并且要精確匹配,包括大小寫。這個錯誤當沒有name屬性和action關聯時也會發生,如果沒有在action中指定name屬性,那么就沒有name屬性和action相關聯。當然當action制作某些控制時,譬如根據參數值跳轉到相應的jsp頁面,而不是處理表單數據,這是就不用name屬性,這也是action的使用方法之一。
          -----------------------------------------------------------------------------------------------------------------
          異常
          No action instance for path /xxxx could be created

          可能原因
          特別提示:因為有很多中情況會導致這個錯誤的發生,所以推薦大家調高你的web服務器的日志/調試級別,這樣可以從更多的信息中看到潛在的、在試圖創建action類時發生的錯誤,這個action類你已經在struts-config.xml中設置了關聯(即添加了<action>標簽)。

          在struts-config.xml中通過action標簽的class屬性指定的action類不能被找到有很多種原因,例如:定位編譯后的.class文件失敗。Failure to place compiled .class file for the action in the classpath (在web開發中,class的的位置在r WEB-INF/classes,所以你的action class必須要在這個目錄下。例如你的action類位于WEB-INF/classes/action/Login.class,那么在struts-config.xml中設置action的屬性type時就是action.Login).
          拼寫錯誤,這個也時有發生,并且不易找到,特別注意第一個字母的大小寫和包的名稱。
          -----------------------------------------------------------------------------------------------------------------
          異常
          javax.servlet.jsp.JspException: No getter method for property username of bean org.apache.struts.taglib.html.BEAN

          可能原因
          沒有位form bean中的某個變量定義getter 方法

          這個錯誤主要發生在表單提交的FormBean中,用struts標記<html:text property=”username”>時,在FormBean中必須有一個getUsername()方法。注意字母“U”。
          -----------------------------------------------------------------------------------------------------------------
          異常
          java.lang.NoClassDefFoundError: org/apache/struts/action/ActionForm

          可能原因
          這個錯誤主要發生在在classpath中找不到相應的Java .class文件。如果這個錯誤發生在web應用程序的運行時,主要是因為指定的class文件不在web server的classpath中(/WEB-INF/classes 和 /WEB-INF/lib)。在上面的錯誤中,原因是找不到ActionForm類。
          -----------------------------------------------------------------------------------------------------------------
          異常
          javax.servlet.jsp.JspException: Exception creating bean of class org.apache.struts.action.ActionForm: {1}

          可能原因
          Instantiating Struts-provided ActionForm class directly instead of instantiating a class derived off ActionForm. This mightoccur implicitly if you specify that a form-bean is this Struts ActionForm class rather than specifying a child of this classfor the form-bean.

          Not associating an ActionForm-descended class with an action can also lead to this error.
          -----------------------------------------------------------------------------------------------------------------
          異常
          javax.servlet.jsp.JspException: Cannot find ActionMappings or ActionFormBeans collection

          可能原因
          不是標識Struts actionServlet的<servlet>標記就是映射.do擴展名的<sevlet-mapping>標記或者兩者都沒有在web.xml中聲明。

          在struts-config.xml中的打字或者拼寫錯誤也可導致這個異常的發生。例如缺少一個標記的關閉符號/>。最好使用struts console工具檢查一下。

          另外,load-on-startup必須在web.xml中聲明,這要么是一個空標記,要么指定一個數值,這個數值用來表servlet運行的優先級,數值越大優先級越低。

          還有一個和使用load-on-startup有關的是使用Struts預編譯JSP文件時也可能導致這個異常。
          -----------------------------------------------------------------------------------------------------------------
          異常
          java.lang.NullPointerException at org.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1223)

          可能原因
          在struts-config.xml中的forward元素缺少path屬性。例如應該是如下形式:
          <forward name="userhome" path="/user/userhome.jsp"/>
          -----------------------------------------------------------------------------------------------------------------
          異常
          javax.servlet.jsp.JspException: Cannot find bean org.apache.struts.taglib.html.BEAN in any scope


           

          Probable Causes
          試圖在Struts的form標記外使用form的子元素。這常常發生在你在</html:form>后面使用Struts的html標記。另外要注意可能你不經意使用的無主體的標記,如<html:form … />,這樣web 服務器解析時就當作一個無主體的標記,隨后使用的所有<html>標記都被認為是在這個標記之外的,如又使用了<html:text property=”id”>還有就是在使用taglib引入HTML標記庫時,你使用的prefix的值不是html。
          -----------------------------------------------------------------------------------------------------------------
          異常
          javax.servlet.jsp.JspException: Missing message for key xx.xx.xx

          Probable Causes
          這個key的值對沒有在資源文件ApplicationResources.properties中定義。如果你使用eclipse時經常碰到這樣的情況,當項目重新編譯時,eclipse會自動將classes目錄下的資源文件刪除。

          資源文件ApplicationResources.properties 不在classpath中應將資源文件放到 WEB-INF/classes 目錄下,當然要在struts-config.xml中定義)
          -----------------------------------------------------------------------------------------------------------------
          異常
          Cannot find message resources under key org.apache.struts.action.MESSAGE

          可能原因
          很顯然,這個錯誤是發生在使用資源文件時,而Struts沒有找到資源文件。

          Implicitly trying to use message resources that are not available (such as using empty html:options tag instead of specifyingthe options in its body -- this assumes options are specified in ApplicationResources.properties file)

          XML parser issues -- too many, too few, incorrect/incompatible versions
          -----------------------------------------------------------------------------------------------------------------
          異常
          Strange and seemingly random characters in HTML and on screen, but not in original JSP or servlet.

          可能原因
          混和使用Struts的html:form標記和標準的HTML標記不正確。

          使用的編碼樣式在本頁中不支持。
          -----------------------------------------------------------------------------------------------------------------
          異常
          "Document contained no data" in Netscape

          No data rendered (completely empty) page in Microsoft Internet Explorer

          可能原因
          使用一個Action的派生類而沒有實現perform()方法或execute()方法。在Struts1.0中實現的是perform()方法,在Struts1.1中實現的是execute()方法,但Struts1.1向后兼容perform()方法。但你使用Struts1.1創建一個Action的派生類,并且實現了execute()方法,而你在Struts1.0中運行的話,就會得到"Document contained nodata" error message in Netscape or a completely empty (no HTML whatsoever) page rendered in Microsoft Internet Explorer.”的錯誤信息。

          ---------------------------------------------------------------------------------------------------------------------------
          異常
          ServletException: BeanUtils.populate
          解決方案
          在用Struts上傳文件時,遇到了javax.servlet.ServletException: BeanUtils.populate異常。
          我的ActionServlet并沒有用到BeanUtils這些工具類。后來仔細檢查代碼發現是在jsp文件里的form忘了加enctype=&quot;multipart/form-data&quot; 了。所以寫程序遇到錯誤或異常應該從多方面考慮問題存在的可能性,想到系統提示信息以外的東西。
          ----------------------------------------------------------------------------------------------------------------------------
          1. 定義Action后, 如果指定了name, 那么必須要定義一個與它同名的FormBean才能進行form映射.2. 如果定義Action后, 提交頁面時出現 "No input attribute for mapping path..." 錯誤, 則需要在其input屬性中定義轉向的頁面.3. 如果插入新的數據時出現 "Batch update row count wrong:..." 錯誤, 則說明XXX.hbm.xml中指定的key的類型為原始類型(int, long),因為這種類型會自動分配值, 而這個值往往會讓系統認為已經存在該記錄, 正確的方法是使用java.lang.Integer或java.lang.Long對象.4. 如果插入數據時出現 "argument type mismatch" 錯誤, 可能是你使用了Date等特殊對象, 因為struts不能自動從String型轉換成Date型,所以, 你需要在Action中手動把String型轉換成Date型.5. Hibernate中, Query的iterator()比list()方法快很多.6. 如果出現 "equal symbol expected" 錯誤, 說明你的strtus標簽中包含另一個標簽或者變量, 例如:
          <html:select property="test" onchange="<%=test%>"/>
          或者
          <html:hidden property="test" value="<bean:write name="t" property="p"/>"/>
          這樣的情況...
          ---------------------------------------------------------------------------------------------------------------------------
          錯誤:Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update原因與解決:      因為Hibernate Tools(或者Eclipse本身的Database Explorer)生成*.hbn.xml工具中包含有catalog="***"(*表示數據庫名稱)這樣的屬性,將該屬性刪除就可以了
          ---------------------------------------------------------------------------------------------------------------------------
          錯誤:org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)
          原因與解決:
          方法1 刪除Set方的cascade
          方法2 解決關聯關系后,再刪除
          方法3 在many-to-one方增加cascade 但值不能是none
          最后一招:
          檢查一下hashCode equals是否使用了id作為唯一標示的選項了;我用uuid.hex時是沒有問題的;但是用了native,就不行了,怎么辦?刪除??!
          ----------------------------------------------------------------------------------------------------------------------------
          問題:今天用Tomcat 5.5.12,發現原來很好用的系統不能用了,反復測試發現頁面中不能包含 taglib,否則會出現以下提示:HTTP Status 500 -type Exception reportMessage description The server encountered an internal error () that prevented it from fulfilling this request.exceptionorg.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD "META-INF/tlds/struts-bean.tld" from JAR file"file:*****/WEB-INF/lib/struts.jar":原因:更新了工程用的lib文件夾下的jar,發布時也發布了servlet.jar和jsp-api.jar。解決:把jsp-api.jar刪除就解決這個問題了。-----------------------------------------------------------------------------------------------------------------------------
          錯誤: java.lang.NullPointerException
          原因: 發現 dao 實例、 manage 實例等需要注入的東西沒有被注入(俗稱空指針異常)解決:這個時候,你應該查看日志文件;默認是應用服務器的 log 文件,比如 Tomcat 就是 [Tomcat 安裝目錄 ]/logs ;你會發現提示你:可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sf' defined in ServletContextresource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xmlorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml……………………….Caused by: java.io.FileNotFoundException: src\hibernate.cfg.xml可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined inServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not foundorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found然后你就知道原因是因為配置文件的解析出了錯誤,這個通過 Web 頁面是看不出來的。更多的是持久化影射文件出的錯誤;導致了沒有被解析;當然你需要的功能就無法使用了。
          ----------------------------------------------------------------------------------------------------------------------------
          錯誤:StandardWrapperValve[action]: Servlet.service() for servlet action threw exception
          javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage
          或者:      type Status report      message Servlet action is not available      description The requested resource (Servlet action is not available) is not available.
          原因: 同 上
          ----------------------------------------------------------------------------------------------------------------------------
          錯誤StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exceptionjava.lang.ClassNotFoundException: org.apache.struts.taglib.bean.CookieTei界面錯誤具體描述:
          org.apache.jasper.JasperException: Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.bean.CookieTei
                原因與解決:    <方案一>你的“html:”開頭的標簽沒有放在一個<html:form>中       <方案二>重新啟動你的應用服務器,自動就沒有這個問題

          posted @ 2007-10-15 13:09 PariScamper 閱讀(1798) | 評論 (0)編輯 收藏

          網上說是數據庫的列名與oracle的保留字重名,的確如此。
          比如我的有一列叫user就是,另外我驗證叫level也是。
          網上有的說叫start和end也不行,但經我試驗,是可以的,也就是start和end不是保留字。
          另外,這個錯誤只在使用hibernate才出現(使用jdbc也可能出現,沒試過)。
          直接用oracle的客戶端Enterprise Manager Console卻沒有這個問題,就是列名叫user和level,照樣可以插入數據。

          posted @ 2007-10-12 23:05 PariScamper 閱讀(6669) | 評論 (0)編輯 收藏

          SQL語句為
          insert into room(id,bid,name) values(room_seq.nextval,12,'1346S');
          room_seq.nextval為取得room_seq的下一值后,取完值后會自動增長
          select room_seq.nextval from dual則選出room_seq的nextval值,取值后也會自動增長
          select room_seq.currval from dual則選出room_seq的當前值,取值后不會自動增長
          另外,Oracle不像其他數據庫,NVARCHAR2的數據類型的取值居然是'abcd'(單引號),既不是雙引號,也不是無引號。

          posted @ 2007-10-12 19:33 PariScamper 閱讀(2354) | 評論 (1)編輯 收藏

          主站蜘蛛池模板: 连城县| 泸定县| 稻城县| 金华市| 龙川县| 黑水县| 遵义县| 白朗县| 班戈县| 江华| 鹤庆县| 新津县| 攀枝花市| 九龙县| 泰安市| 东丰县| 沙湾县| 砀山县| 措美县| 霍邱县| 丹巴县| 乾安县| 乐昌市| 新和县| 荥经县| 西盟| 杨浦区| 桃园市| 新沂市| 丹江口市| 永川市| 康乐县| 依兰县| 闸北区| 商都县| 通榆县| 明星| 琼结县| 洪雅县| 新野县| 高密市|