1.1描寫properties文件。
          這個(gè)描述文件一般放在可以放在兩個(gè)地方:(1)WEB-INF/classes目錄下,或者放在在/project_root/,也就是你的web_app的根目錄下。利用這個(gè)控制日志紀(jì)錄的配置,當(dāng)然也可以通過xml文件配置,這里我們暫且說說properties的配置。
          建立文件名log4j.properties文件。放在%tomca_home%/web_app/fcxtest/目錄下。
          文件內(nèi)容如下:(fcxtest為自己建立的web app目錄)

          #--------------------------------
          # 設(shè)定logger的root level為DEBUG,指定的輸出目的地(appender)為A1
          log4j.rootLogger=DEBUG, A1

          # 設(shè)定調(diào)試信息的輸出位置,此處設(shè)定輸出為控制臺(tái)
          log4j.appender.A1=org.apache.log4j.ConsoleAppender

          # 設(shè)定調(diào)試信息的輸出位置,此處設(shè)定輸出為fcxtest.log文件
          # log4j.appender.A1=org.apache.log4j.RollingFileAppender
          # log4j.appender.A1.File=fcxtest.log
          # log4j.appender.A1.MaxFileSize=1000KB

          # 設(shè)定制定的A1使用的PatternLayout.
          # 有關(guān)ConversionPattern中的轉(zhuǎn)意字符的含義參考說明
          log4j.appender.A1.layout=org.apache.log4j.PatternLayout
          log4j.appender.A1.layout.ConversionPattern=%d %-5p [%t] %C{2} (%F:%L) - %m%n
          #--------------------------------

          1.2建立測試用的Servlet類
          這個(gè)測試的com.fcxlog.LogShow類主要是顯示如何使用log4j。

          package com.fcxlog;

          import javax.servlet.*;
          import javax.servlet.http.*;

          import org.apache.log4j.Logger;
          import org.apache.log4j.BasicConfigurator;
          import org.apache.log4j.PropertyConfigurator;

          public class LogShow extends javax.servlet.http.HttpServlet{

          protected String configfile = "log4j.properties";

          public void init() throws ServletException{
          ServletContext sct = getServletContext();
          System.out.println("[Log4j]: The Root Path: " + sct.getRealPath("/"));
          //指定自己的properties文件
          //以前使用的是BasicConfigurator.configure(),現(xiàn)在使用PropertyConfigurator替代
          org.apache.log4j.PropertyConfigurator.configure(sct.getRealPath("/") + configfile);
          }

          public void service(javax.servlet.http.HttpServletRequest req,javax.servlet.http.HttpServletResponse res){

          //初始化Logger,以前使用Category,現(xiàn)在改用Logger替代
          //org.apache.log4j.Category log = org.apache.log4j.Category.getInstance(LogShow.class);
          org.apache.log4j.Logger log = ora.apache.log4j.Logger.getLogger(LogShow.class);
          log.info("調(diào)試信息");

          }
          }

          1.3 測試了
          至于如何測試,發(fā)布,就不說了。

          在此說明:
          (1)本篇可能錯(cuò)誤不少,一方面是參考《Short introduction to log4j》著翻譯了一點(diǎn),有諸多言辭不妥之處,還望指正。一方面,憑借自己的理解,所以難免有不全的地方,還望各位補(bǔ)充。
          (2)因?yàn)闀r(shí)間有限,每天只能寫一點(diǎn),本文主要是介紹有關(guān)Logger及Logger level相關(guān)概念的
          (3)有關(guān)Log4j介紹(一),請參閱:http://www.javaren.com/bbs/cgi-bin/topic.cgi?forum=1&topic=12766&show=0#lastviewpost


          概述:
          本文主要是簡要的介紹了Log4j的api,以及其一些特征和設(shè)計(jì)原理。它本身是一個(gè)開源的軟件,允許開發(fā)者任意的操縱應(yīng)用系統(tǒng)日志信息。Log4j的使用通過外部配置文件進(jìn)行配置。

          任何大型應(yīng)用系統(tǒng)都有其自己的系統(tǒng)日志管理或跟蹤的API,所以在1996年的時(shí)候,E.U. SEMPER項(xiàng)目組(http://www.semper.org/)也開發(fā)其自己的日志管理API,后來經(jīng)過無數(shù)次的修改和補(bǔ)充,發(fā)展成了現(xiàn)在的log4j,一個(gè)給予java的日志管理工具包。有關(guān)最新的版本信息和源碼,請?jiān)L問http://jakarta.apache.org/log4j/docs/index.html
          把紀(jì)錄語句放在代碼之中,是一種低端的調(diào)試方法,不過有時(shí)卻不得不說是很有效,也是必需的。畢竟很多時(shí)候,調(diào)試器并不見得很適用。特別是在多線程應(yīng)用程序(multithread application)或分布式應(yīng)用程序(distributed application)

          經(jīng)驗(yàn)告訴我們,在軟件開發(fā)生命周期中,日志系統(tǒng)是一個(gè)非常重要的組件。當(dāng)然,日志系統(tǒng)也有其自身的問題,過多的日志紀(jì)錄會(huì)降低系統(tǒng)運(yùn)行的速度。

          (一)Log4j的三個(gè)重要組件?? Loggers, Appenders, Layouts

          這三個(gè)組件協(xié)同的工作,使得開發(fā)者能夠依據(jù)信息類別和級別去紀(jì)錄信息,并能夠運(yùn)行期間,控制信息記錄的方式已經(jīng)日志存放地點(diǎn)。

          (二)記錄器層次(Logger hierarchy)

          幾乎任何紀(jì)錄日志的API得功能都超越了簡單的System.out.print語句。允許有選擇控制的輸出日志信息,也就是說,某的時(shí)候,一些日志信息允許輸出,而另一些則不允許輸出。這就假設(shè)日志紀(jì)錄信息之間是有分別的,根據(jù)開發(fā)者自己定義的選擇標(biāo)準(zhǔn),可以對日志信息加以分類。

          紀(jì)錄器的命名是依據(jù)實(shí)體的。下面有一段有點(diǎn)繞口的解釋,我就直抄了,各位可以看看:(Name Hierarchy)A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger.
          (形象的解釋,比如存在記錄器 a.b.c,記錄器a.b,記錄器a。那么a就是a.b的ancestor,而a.b就是a.b.c的parent,而a.b.c就是a.b的child)

          根紀(jì)錄器(root logger)是記錄器層次的頂端。它有兩個(gè)獨(dú)特點(diǎn):(1)總是存在的(2)能夠被重新找回??梢酝ㄟ^訪問類的靜態(tài)方法 Logger.getRootLogger 重新得到。其他的紀(jì)錄器通過訪問靜態(tài)方法 Logger.getLogger 被實(shí)例話或被得到,這個(gè)方法將希望獲得的記錄器的名稱作為參數(shù)。一些Logger類的方法描述如下:
          public class Logger {
          // Creation & retrieval methods:
          public static Logger getRootLogger();
          public static Logger getLogger(String name);
          // printing methods:
          public void debug(Object message);
          public void info(Object message);
          public void warn(Object message);
          public void error(Object message);
          public void fatal(Object message);

          // generic printing method:
          public void log(Level l, Object message);
          }

          記錄器被賦予級別,這里有一套預(yù)定的級別標(biāo)準(zhǔn):DEBUG, INFO, WARN, ERROR and FATAL ,這些是在 org.apache.log4j.Level 定義的。你可以通過繼承Level類定義自己的級別標(biāo)準(zhǔn),雖然并不鼓勵(lì)這么做。
          如果給定的記錄器沒有被賦予級別,則其會(huì)從離其最近的擁有級別的ancestor處繼承得到。如果ancestor也沒有被賦予級別,那么就從根記錄器繼承。所以通常情況下,為了讓所有的記錄器最終都能夠被賦予級別,跟記錄器都會(huì)被預(yù)先設(shè)定級別的。比如我們在操作properties文件中,會(huì)寫這么一句:log4j.rootLogger=DEBUG, A1 。實(shí)際上就這就指定了root Logger和root Logger level。

          Appenders
          Log4j允許記錄信息被打印到多個(gè)輸出目的地,一個(gè)輸出目的地叫做Appender。目前的Log4j存在的輸出目的地包括:控制臺(tái)(Console),文件(File),GUI Componennt,Remote Socket Server,JMS,NT Event Logger,and Remote Unix Syslog daemons。
          多個(gè)Appender可以綁定到一個(gè)記錄器上(Logger)。

          通過方法 addAppender(Logger.addAppender) 可以將一個(gè)Appender附加到一個(gè)記錄器上。每一個(gè)有效的發(fā)送到特定的記錄器的記錄請求都被轉(zhuǎn)送到那個(gè)與當(dāng)前記錄器所綁定的Appender上。(Each enabled logging request for a given logger will be forwarded to all the appenders in that logger as well as the appenders higher in the hierarchy),換句話說,Appender的繼承層次是附加在記錄器繼承層次上的。舉個(gè)例子:如果一個(gè)Console Appender被綁定到根記錄器(root Logger),那么所有的記錄請求都可以至少被打印到Console。另外,把一個(gè)file Appender綁定到記錄器C,那么針對記錄器C(或C的子孫)的記錄請求都可以至少發(fā)送到Console Appender和file Appender。當(dāng)然這種默認(rèn)的行為方式可以跟改,通過設(shè)定記錄器的additivity flag(Logger.setAdditivity)為false,從而可以使得Appender的不再具有可加性(Additivity)。
          下面簡要介紹一下Appender Additivity。

          Appender Additivity:記錄器C所記錄的日志信息將被發(fā)送到與記錄器C以及其祖先(ancestor)所綁定的所有Appender。
          但是,如果記錄器C的祖先,叫做P,它的additivity flag被設(shè)定為false。那么,記錄信息仍然被發(fā)送到與記錄器C及其祖先,但只到達(dá)P這一層次,包括P在內(nèi)的記錄器的所有Appender。但不包括P祖先的。
          通常,記錄器的additivity flag的被設(shè)置為true。


          Layouts
          這一塊主要是介紹輸出格式的。PatternLayout,Log4j標(biāo)準(zhǔn)的分配器,可以讓開發(fā)者依照conversion patterns去定義輸出格式。Conversion patterns有點(diǎn)像c語言的打印函數(shù)。
          參看配置文件的java properties,如下面的兩行:
          log4j.appender.A1.layout=org.apache.log4j.PatternLayout
          log4j.appender.A1.layout.ConversionPattern=%d %-5p [%t] %C{2} (%F:%L) - %m%n
          第一行就指定了分配器,第二行則指定了輸出的格式。
          有關(guān)輸出格式的定義可以參考/org/apache/log4j/PatternLayout.html
          更基礎(chǔ)的知識(shí),可以到田貫升門診室,另有一篇偏重基礎(chǔ)的介紹~??
          posted @ 2006-05-30 16:53 edsonjava 閱讀(236) | 評論 (0)編輯 收藏
           
          1.1準(zhǔn)備工作
          一。Tomcat已正確配置與使用。
          二。軟件下載:log4j------http://www.apache.org/dist/jakarta/log4j/jakarta-log4j-1.2.8.zip

          1.2. Log4j簡介

          在強(qiáng)調(diào)可重用組件開發(fā)的今天,除了自己從頭到尾開發(fā)一個(gè)可重用的日志操作類外,Apache為我們提供了一個(gè)強(qiáng)有力的日志操作包-Log4j。
          Log4j是Apache的一個(gè)開放源代碼項(xiàng)目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺(tái)、文件、GUI組件、甚至是套接口服務(wù)器、NT的事件記錄器、UNIX Syslog守護(hù)進(jìn)程等;我們也可以控制每一條日志的輸出格式;通過定義每一條日志信息的級別,我們能夠更加細(xì)致地控制日志的生成過程。最令人感興趣的就是,這些可以通過一個(gè)配置文件來靈活地進(jìn)行配置,而不需要修改應(yīng)用的代碼。
          此外,通過Log4j其他語言接口,您可以在C、C++、.Net、PL/SQL程序中使用Log4j,其語法和用法與在Java程序中一樣,使得多語言分布式系統(tǒng)得到一個(gè)統(tǒng)一一致的日志組件模塊。而且,通過使用各種第三方擴(kuò)展,您可以很方便地將Log4j集成到J2EE、JINI甚至是SNMP應(yīng)用中。本文介紹的Log4j版本是1.2.8,怎樣通過一個(gè)配置文件來靈活地進(jìn)行配置,主要的應(yīng)用平臺(tái)是Tomcat4.

          1.3。Log4j的配置。

          首先到j(luò)akarta下載一個(gè)log4j的組件。把jakarta-log4j-1.2.8\dist\lib下的log4j-1.2.8.jar文件copy到classpath指定的目錄下!可以是Tomcat的common\lib目錄下,也可以是你需要用到log4j的application下的lib目錄。
          1.4在Application目錄下的web.xml文件加入以后代碼

          log4j
          com.apache.jakarta.log4j.Log4jInit

          log4j
          /WEB-INF/log4j.properties

          1


          這段代碼的意思是說,在Tomcat啟動(dòng)時(shí)加載com.apache.jakarta.log4j.Log4jInit這個(gè)名叫Log4jInit.class這個(gè)類文件。其中Log4jInit.class的源代碼如下

          package com.apache.jakarta.log4j;
          import org.apache.log4j.PropertyConfigurator;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          public class Log4jInit extends HttpServlet {

          public void init() {
          String prefix = getServletContext().getRealPath("/");
          String file = getInitParameter("log4j");
          // if the log4j-init-file is not set, then no point in trying
          System.out.println("................log4j start");
          if(file != null) {
          PropertyConfigurator.configure(prefix+file);
          }
          }
          public void doGet(HttpServletRequest req, HttpServletResponse res) {
          }
          }
          這段代碼很簡單,可以看出,在加載的過程中,程序會(huì)讀取/WEB-INF/log4j.properties這個(gè)文件
          這個(gè)文件就是本文的重點(diǎn),也就是log4j的配置文件。

          # Set root logger level to DEBUG and its only appender to A1
          #log4j中有五級logger
          #FATAL 0
          #ERROR 3
          #WARN 4
          #INFO 6
          #DEBUG 7
          #配置根Logger,其語法為:
          #log4j.rootLogger = [ level ] , appenderName, appenderName, …
          log4j.rootLogger=INFO, A1 ,R
          #這一句設(shè)置以為著所有的log都輸出
          #如果為log4j.rootLogger=WARN, 則意味著只有WARN,ERROR,FATAL
          #被輸出,DEBUG,INFO將被屏蔽掉.
          # A1 is set to be a ConsoleAppender.
          #log4j中Appender有幾層如控制臺(tái)、文件、GUI組件、甚至是套接口服務(wù)器、NT的事件記錄器、UNIX Syslog守護(hù)進(jìn)程等
          #ConsoleAppender輸出到控制臺(tái)
          log4j.appender.A1=org.apache.log4j.ConsoleAppender
          # A1 使用的輸出布局,其中l(wèi)og4j提供4種布局. org.apache.log4j.HTMLLayout(以HTML表格形式布局)
          #org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
          #org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
          #org.apache.log4j.TTCCLayout(包含日志產(chǎn)生的時(shí)間、線程、類別等等信息)

          log4j.appender.A1.layout=org.apache.log4j.PatternLayout
          #靈活定義輸出格式 具體查看log4j javadoc org.apache.log4j.PatternLayout
          #d 時(shí)間 ....
          log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
          #R 輸出到文件 RollingFileAppender的擴(kuò)展,可以提供一種日志的備份功能。
          log4j.appender.R=org.apache.log4j.RollingFileAppender
          #日志文件的名稱
          log4j.appender.R.File=log4j.log
          #日志文件的大小
          log4j.appender.R.MaxFileSize=100KB
          # 保存一個(gè)備份文件
          log4j.appender.R.MaxBackupIndex=1

          log4j.appender.R.layout=org.apache.log4j.TTCCLayout
          #log4j.appender.R.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

          配置以這里就差不多了,如果你想更深入了解配置文件的各個(gè)細(xì)節(jié),可以去查看docs。還有,在文章的最后面我們提供配置文件中一些主要的語法。下面我們來看看怎樣在程序中使用log4j.

          1.4 Log4j的使用。
          使用Log4j,第一步就是獲取日志記錄器,這個(gè)記錄器將負(fù)責(zé)控制日志信息。其語法為:
          public static Logger getLogger( String name),
          必須在使用前要把這個(gè)類導(dǎo)入
          import org.apache.log4j.Logger;

          name一般是類文件的名字,如下:
          static Logger logger = Logger.getLogger ("".class.getName () ) ;

          您就可以輕松地使用不同優(yōu)先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
          logger.debug ( Object message ) ;
          logger.info ( Object message ) ;
          logger.warn ( Object message ) ;
          logger.error ( Object message ) ;

          為什么這里要分級別的呢?試想一下,我們在寫程序的時(shí)候,為了調(diào)試程序,會(huì)在很多會(huì)出錯(cuò)的地方加入大量的logger.info();信息。當(dāng)然程序調(diào)試完畢,我們不需要這些輸出信息了,那怎么辦呢?以前的做法是把每個(gè)程序中的logger.info刪除,但這是不現(xiàn)實(shí)的,如果程序不大還可以,但如果程序很多,做這些事情就很煩人了。但因?yàn)閘og4j分級別了,當(dāng)我們不需要輸出這樣調(diào)試時(shí)用到的log.info()時(shí),我們可以把輸出的級別調(diào)高,如調(diào)到warn,或error級別,這樣info級別及以下的級別就不會(huì)出輸出了,是不是很方便的呢?

          其實(shí)除了這種使用方式,log4j還有其它的使用方面,不需要配置文件,直接在程序中定義輸入出級別,層次等信息,如果要了解這方法的使用,可以參考文檔。

          1.5。附注:
          以下是配置文件的一些重要的語法
          定義配置文件

          其實(shí)您也可以完全不使用配置文件,而是在代碼中配置Log4j環(huán)境。但是,使用配置文件將使您的應(yīng)用程序更加靈活。

          Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:

          配置根Logger,其語法為:

          log4j.rootLogger = [ level ] , appenderName, appenderName, …
          其中,level 是日志記錄的優(yōu)先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個(gè)級別,優(yōu)先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應(yīng)用程序中相應(yīng)級別的日志信息的開關(guān)。比如在這里定義了INFO級別,則應(yīng)用程序中所有DEBUG級別的日志信息將不被打印出來。
          appenderName就是指定日志信息輸出到哪個(gè)地方。您可以同時(shí)指定多個(gè)輸出目的地。

          配置日志信息輸出目的地Appender,其語法為

          log4j.appender.appenderName = fully.qualified.name.of.appender.class
          log4j.appender.appenderName.option1 = value1

          log4j.appender.appenderName.option = valueN
          其中,Log4j提供的appender有以下幾種:
          org.apache.log4j.ConsoleAppender(控制臺(tái)),
          org.apache.log4j.FileAppender(文件),
          org.apache.log4j.DailyRollingFileAppender(每天產(chǎn)生一個(gè)日志文件),org.apache.log4j.RollingFileAppender(文件大小到達(dá)指定尺寸的時(shí)候產(chǎn)生一個(gè)新的文件),
          org.apache.log4j.WriterAppender(將日志信息以流格式發(fā)送到任意指定的地方)

          配置日志信息的格式(布局),其語法為:

          log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
          log4j.appender.appenderName.layout.option1 = value1

          log4j.appender.appenderName.layout.option = valueN
          其中,Log4j提供的layout有以下幾種:
          org.apache.log4j.HTMLLayout(以HTML表格形式布局),
          org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
          org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
          org.apache.log4j.TTCCLayout(包含日志產(chǎn)生的時(shí)間、線程、類別等等信息)

          posted @ 2006-05-30 16:30 edsonjava 閱讀(175) | 評論 (0)編輯 收藏
           
          log4j在web端的使用技巧!

          log4j的好處在于:

          1.

          通過修改配置文件,就可以決定log信息輸出到何處(console,文件,...),是否輸出。
          這樣,在系統(tǒng)開發(fā)階段可以打印詳細(xì)的log信息以跟蹤系統(tǒng)運(yùn)行情況,而在系統(tǒng)穩(wěn)定后可以關(guān)閉log輸出,從而在能跟蹤系統(tǒng)運(yùn)行情況的同時(shí),又減少了垃圾代碼(System.out.println(...)等)。

          2.

          使用log4j,需要整個(gè)系統(tǒng)有一個(gè)統(tǒng)一的log機(jī)制,有利于系統(tǒng)的規(guī)劃。

          log4j的使用本身很簡單。但合理地規(guī)劃一個(gè)系統(tǒng)的統(tǒng)一log機(jī)制需要周全的考慮。

          其他關(guān)于log4j的信息參看log4j自帶的文檔。

          PART?II?配置文件詳細(xì)解釋
          先看一個(gè)配置文件的例子:

          1.

          配置文件的例子

          log4j.rootLogger=DEBUG
          #將DAO層log記錄到DAOLog,allLog中
          log4j.logger.DAO=DEBUG,A2,A4
          #將邏輯層log記錄到BusinessLog,allLog中
          log4j.logger.Businesslog=DEBUG,A3,A4

          #A1--打印到屏幕上
          log4j.appender.A1=org.apache.log4j.ConsoleAppender
          log4j.appender.A1.layout=org.apache.log4j.PatternLayout
          log4j.appender.A1.layout.ConversionPattern=%-5p?[%t]?%37c?%3x?-?%m%n

          #A2--打印到文件DAOLog中--專門為DAO層服務(wù)log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.A2.file=DAOLog
          log4j.appender.A2.DatePattern='.'yyyy-MM-dd
          log4j.appender.A2.layout=org.apache.log4j.PatternLayout
          log4j.appender.A2.layout.ConversionPattern=[%-5p]?%d{yyyy-MM-dd?HH:mm:ss,SSS}?method:%l%n%m%n

          #A3--打印到文件BusinessLog中--專門記錄邏輯處理層服務(wù)log信息log4j.appender.A3=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.A3.file=BusinessLog
          log4j.appender.A3.DatePattern='.'yyyy-MM-dd
          log4j.appender.A3.layout=org.apache.log4j.PatternLayout
          log4j.appender.A3.layout.ConversionPattern=[%-5p]?%d{yyyy-MM-dd?HH:mm:ss,SSS}?method:%l%n%m%n

          #A4--打印到文件alllog中--記錄所有l(wèi)og信息log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.A4.file=alllog
          log4j.appender.A4.DatePattern='.'yyyy-MM-dd
          log4j.appender.A4.layout=org.apache.log4j.PatternLayout
          log4j.appender.A4.layout.ConversionPattern=[%-5p]?%d{yyyy-MM-dd?HH:mm:ss,SSS}?method:%l%n%m%n

          2.

          Appender的使用
          一個(gè)Appender代表log信息要寫向的一個(gè)地方。log4j可使用的Appender有很多類型,這里只考慮3種:ConsoleAppender,FileAppender,DailyRollFileAppender
          2.1
          ?ConsoleAppender
          如果使用ConsoleAppender,那么log信息將寫到Console。就是直接把信息打印到System.out上了。
          2.2?
          FileAppender
          使用FileAppender,那么log信息將寫到指定的文件中。這應(yīng)該是比較經(jīng)常使用到的情況。
          相應(yīng)地,在配置文件中應(yīng)該指定log輸出的文件名。如下配置指定了log文件名為demo.txt
          log4j.appender.A2.File=demo.txt
          注意將A2替換為具體配置中Appender的別名。
          2.3
          ?DailyRollingAppender
          使用FileAppender可以將log信息輸出到文件中,但是如果文件太大了讀起來就不方便了。這時(shí)就可以使用DailyRollingAppender。DailyRollingAppender可以把Log信息輸出到按照日期來區(qū)分的文件中。如下配置文件就會(huì)每天產(chǎn)生一個(gè)log文件,每個(gè)log文件只記錄當(dāng)天的log信息:

          1. log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender
          2. log4j.appender.A2.file=demo
          3. log4j.appender.A2.DatePattern='.'yyyy-MM-dd
          4. log4j.appender.A2.layout=org.apache.log4j.PatternLayout
          5. log4j.appender.A2.layout.ConversionPattern=%m%n


          3.

          Layout的配置
          Layout指定了log信息輸出的樣式。
          詳細(xì)信息請查看PatternLayout的javadoc。
          例子1:顯示日期和log信息
          1. log4j.appender.A2.layout=org.apache.log4j.PatternLayout
          2. log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd?HH:mm:ss,SSS}?%m%n

          打印的信息是:
          2002-11-12?11:49:42,866?SELECT?*?FROM?Role?WHERE?1=1?order?by?createDate?desc

          例子2:顯示日期,log發(fā)生地方和log信息
          1. log4j.appender.A2.layout=org.apache.log4j.PatternLayout
          2. log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd?HH:mm:ss,SSS}?%l?"#"?%m%n
          3. 2002-11-12?11:51:46,313?cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409)?"#"?SELECT?*?FROM?Role?WHERE?1=1?order?by?createDate?desc?

          例子3:顯示log級別,時(shí)間,調(diào)用方法,log信息
          1. log4j.appender.A2.layout=org.apache.log4j.PatternLayout
          2. log4j.appender.A2.layout.ConversionPattern=[%-5p]?%d{yyyy-MM-dd?HH:mm:ss,SSS}?method:%l%n%m%nlog信息:[DEBUG]?2002-11-12?12:00:57,376?method:cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409)
          3. SELECT?*?FROM?Role?WHERE?1=1?order?by?createDate?desc?


          PART?3?log4j的使用
          log4j使用步驟有3個(gè):
          3.1
          .根據(jù)配置文件初始化log4j
          配置文件如PART?2所敘述?,F(xiàn)在講的是如何在程序中配置log4j。
          log4j可以使用3中配置器來初始化:BasicConfigurator,DOMConfigurator,PropertyConfigurator
          這里用的是PropertyConfigurator。使用PropertyConfigurator適用于所有的系統(tǒng)。
          如下的語句
          PropertyConfigurator.configure("log4j.properties");
          就以log4j.properties為配置文件初始化好了log4j環(huán)境。
          注意一點(diǎn):這個(gè)語句只需要在系統(tǒng)啟動(dòng)的時(shí)候執(zhí)行一次。例如:在unet?webOA項(xiàng)目中可以這么用:
          在ActionServlet的init()方法中調(diào)用一次。
          public?class?ActionServlet?extends?HttpServlet{
          /***?Initialize?global?variables*/
          public?void?init()?throws?ServletException?{
          //?初始化Action資源
          try{initLog4j();...}
          catch(IOException?e)
          {throw?new?ServletException("Load?ActionRes?is?Error");}}
          protected?void?initLog4j(){PropertyConfigurator.configure("log4j.properties");}
          }
          //end?class?ActionServlet

          3.2?
          在需要使用log4j的地方獲取Logger實(shí)例
          如下是RoleDAO類中的使用例子:
          static?Logger?log?=?Logger.getLogger("DAO");
          注意這里使用"DAO"標(biāo)識(shí)符,那么對應(yīng)的在配置文件中對應(yīng)的配置信息如下:

          #定義DAO?Logger
          log4j.logger.DAO=DEBUG,A2
          #設(shè)置Appender?A2的屬性
          log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.A2.file=demolog4j.appender.A2.DatePattern='.'yyyy-MM-ddlog4j.appender.A2.layout=org.apache.log4j.PatternLayout
          log4j.appender.A2.layout.ConversionPattern=%-5p?%d{yyyy-MM-dd?HH:mm:ss}?%l%n%m%n
          public?class?RoleDAO?extends?BaseDBObject{...static?Logger?log?=?Logger.getLogger("DAO");
          public?BeanCollection?selectAll()?throws?SQLException{
          StringBuffer?sql?=?new?StringBuffer(SQLBUF_LEN);sql.append("SELECT?*?FROM?"?+?tableName?+?"?order?by?roldId");
          //System.out.println(sql.toString());log.debug(sql);
          }
          }

          3.3?
          使用Logger對象的debug,info,fatal...方法
          log.debug("it?is?the?debug?info");

          附件1:log4j的一個(gè)bug
          當(dāng)這樣使用時(shí),DailyRollingFileAppender不能正確使用:
          public?Class?RoleDAO(){
          static?Logger?log?=?Logger.getLogger("DAO");
          //在每一次new?RoleDAO對象的時(shí)候都執(zhí)行一次configure()操作
          public?RoleDAO(TransactionManager?transMgr)?throws?SQLException{...PropertyConfigurator.configure("log4j.properties");}
          public?void?select(){...//使用log4j進(jìn)行l(wèi)og記錄log.debug("...");
          }
          }

          ?1.?不需要顯式編碼去初始化?log4j,只要你的配置文件放在?CLASSPATH的目錄下就可以了.
          ?2.用common?log而不要直接用log4j的?Logger?logger?=?XXX,?例子如下:
          ???在類?ThisIsMyClass?的代碼中:
          ???private?static?Log?log?=?LogFactory.getLog(ThisIsMyClass.class);

          ???log4j?就會(huì)自動(dòng)用步驟1所述方法初始化.

          ???用ThisIsMyClass.class作為參數(shù)去取得一個(gè)Log對象,
          ???好處就是可以更靈活地在?log4j?配置文件中配置相應(yīng)的?appender?和?logger?
          posted @ 2006-05-30 16:23 edsonjava 閱讀(325) | 評論 (0)編輯 收藏
           
          基于 Java 開發(fā)的論壇,最有名的當(dāng)屬 Jive ,國產(chǎn)的 Jute 也很不錯(cuò)。好是好,但需要花費(fèi)銀子才能用。對于企業(yè),應(yīng)該考慮使用Jute,因?yàn)槠涮岣吡己玫募夹g(shù)支持。對于個(gè)人,或許就不值得了。這里推薦開源項(xiàng)目 mvnForum, 基于 J2EE technology (Jsp/Servlet).

          mvnFourm is free, opensource and released under the terms of the GNU General Public License. It means that you could use it free of charge to build your own discussion communities.

          一、簡介

          mvnForum 基于Jsp/Servlet開發(fā),支持Jsp 1.2 和 Servlet 2.3,安裝和使用都非常簡單。

            主要特征:

          • 基于 MVC 架構(gòu)
          • 內(nèi)建數(shù)據(jù)庫連接池
          • 多種數(shù)據(jù)庫 (DB2, MySQL, Oracle 8i/9i, Sql Server, postgreSQL, hsqldb, Interbase/Firebird, SAPDB)
          • 國際化 (支持14種語言: English, 簡體, 繁體等等)
          • Jakarta Common Logging
          這里可以查看論壇功能和全部特征。

          二、安裝環(huán)境

          ? 參考
          服務(wù)器:tomcat 4.1.27 http://jakarta.apache.org/tomcat/index.html
          數(shù)據(jù)庫:PostgreSQL 7.3.3 http://www.postgresql.org

          三、安裝

          1、下載mvnForum 1.0.0 RC 1,如果需要源碼,可以下載mvnForum 1.0.0 RC 1 Source
          2、將mvnforum-1.0.0-rc1.zip截壓縮到mvnforum-1.0.0-rc1目錄。把mvnforum-1.0.0-rc1/webapp目錄復(fù)制到tomcat/webapps/目錄下,然后將webapp改名為mvnforum(可根據(jù)需要改成任意的名稱)。接著把mvnforum-1.0.0-rc1/driver/postgresql.jar復(fù)制到tomcat/webapps/mvnforum/WEB-INF/lib/目錄下。
          3、建立論壇數(shù)據(jù)庫表。首先在PostgreSQL創(chuàng)建一數(shù)據(jù)庫mvnForum,執(zhí)行命令如下:
          CREATEDB -E unicode mvnForum
          接著執(zhí)行mvnforum-1.0.0-rc1/sql/mvnForum_postgresql.sql文件,創(chuàng)建表,執(zhí)行命令如下:
          #psql mvnForum
          mvnForum=#\i mvnForum_postgresql.sql
          4、修改tomcat/webapps/mvnforum/WEB-INF/class/mvncore_db_DBOptions.properties文件,這個(gè)文件配置與數(shù)據(jù)庫相關(guān)的資料。設(shè)置內(nèi)容如下:
          DRIVER_CLASS_NAME = org.postgresql.Driver
          DATABASE_URL = jdbc:postgresql://192.168.0.10:5432/mvnForum
          DATABASE_USER = postgres
          DATABASE_PASSWORD =
          5、基本安裝完成,啟動(dòng)Tomcat,通過http://localhost:8080/mvnforum/index.jsp就可以訪問論壇了。
          6、管理員管理,http://localhost:8080/mvnforum/mvnforumadmin/index。用戶名和密碼都是admin,管理員登陸后可以增加版面和管理用戶了。

          posted @ 2006-05-30 15:28 edsonjava 閱讀(266) | 評論 (0)編輯 收藏
           
          <object id="player" height="64" width="260" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6">
          ????<param NAME="AutoStart" VALUE="-1">
          ????<!--是否自動(dòng)播放-->
          ????<param NAME="Balance" VALUE="0">
          ????<!--調(diào)整左右聲道平衡,同上面舊播放器代碼-->
          ????<param name="enabled" value="-1">
          ????<!--播放器是否可人為控制-->
          ????<param NAME="EnableContextMenu" VALUE="-1">
          ????<!--是否啟用上下文菜單-->
          ????<param NAME="url" VALUE="http://download.xaonline.com/music/huangpy/lover/HPY01.wma">
          ????<!--播放的文件地址-->
          ????<param NAME="PlayCount" VALUE="1">
          ????<!--播放次數(shù)控制,為整數(shù)-->
          ????<param name="rate" value="1">
          ????<!--播放速率控制,1為正常,允許小數(shù),1.0-2.0-->
          ????<param name="currentPosition" value="0">
          ????<!--控件設(shè)置:當(dāng)前位置-->
          ????<param name="currentMarker" value="0">
          ????<!--控件設(shè)置:當(dāng)前標(biāo)記-->
          ????<param name="defaultFrame" value="">
          ????<!--顯示默認(rèn)框架-->
          ????<param name="invokeURLs" value="0">
          ????<!--腳本命令設(shè)置:是否調(diào)用URL-->
          ????<param name="baseURL" value="">
          ????<!--腳本命令設(shè)置:被調(diào)用的URL-->
          ????<param name="stretchToFit" value="0">
          ????<!--是否按比例伸展-->
          ????<param name="volume" value="50">
          ????<!--默認(rèn)聲音大小0%-100%,50則為50%-->
          ????<param name="mute" value="0">
          ????<!--是否靜音-->
          ????<param name="uiMode" value="mini">
          ????<!--播放器顯示模式:Full顯示全部;mini最簡化;None不顯示播放控制,只顯示視頻窗口;invisible全部不顯示-->
          ????<param name="windowlessVideo" value="0">
          ????<!--如果是0可以允許全屏,否則只能在窗口中查看-->
          ????<param name="fullScreen" value="0">
          ????<!--開始播放是否自動(dòng)全屏-->
          ????<param name="enableErrorDialogs" value="-1">
          ????<!--是否啟用錯(cuò)誤提示報(bào)告-->
          ????<param name="SAMIStyle" value>
          ????<!--SAMI樣式-->
          ????<param name="SAMILang" value>
          ????<!--SAMI語言-->
          ????<param name="SAMIFilename" value>
          ????<!--字幕ID-->
          </object>

          1.avi格式

          <object id="video" width="400" height="200" border="0" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA">
          <param name="ShowDisplay" value="0">
          <param name="ShowControls" value="1">
          <param name="AutoStart" value="1">
          <param name="AutoRewind" value="0">
          <param name="PlayCount" value="0">
          <param name="Appearance value="0 value=""">
          <param name="BorderStyle value="0 value=""">
          <param name="MovieWindowHeight" value="240">
          <param name="MovieWindowWidth" value="320">
          <param name="FileName" value="file:///D|/work/vod/Mbar.avi">
          <embed width="400" height="200" border="0" showdisplay="0" showcontrols="1" autostart="1" autorewind="0" playcount="0" moviewindowheight="240" moviewindowwidth="320" filename="file:///D|/work/vod/Mbar.avi" src="Mbar.avi">
          </embed>
          </object>

          2.mpg格式

          <object classid="clsid:05589FA1-C356-11CE-BF01-00AA0055595A" id="ActiveMovie1" width="239" height="250">
          <param name="Appearance" value="0">
          <param name="AutoStart" value="-1">
          <param name="AllowChangeDisplayMode" value="-1">
          <param name="AllowHideDisplay" value="0">
          <param name="AllowHideControls" value="-1">
          <param name="AutoRewind" value="-1">
          <param name="Balance" value="0">
          <param name="CurrentPosition" value="0">
          <param name="DisplayBackColor" value="0">
          <param name="DisplayForeColor" value="16777215">
          <param name="DisplayMode" value="0">
          <param name="Enabled" value="-1">
          <param name="EnableContextMenu" value="-1">
          <param name="EnablePositionControls" value="-1">
          <param name="EnableSelectionControls" value="0">
          <param name="EnableTracker" value="-1">
          <param name="Filename" value="../../../mpeg/halali.mpg" valuetype="ref">
          <param name="FullScreenMode" value="0">
          <param name="MovieWindowSize" value="0">
          <param name="PlayCount" value="1">
          <param name="Rate" value="1">
          <param name="SelectionStart" value="-1">
          <param name="SelectionEnd" value="-1">
          <param name="ShowControls" value="-1">
          <param name="ShowDisplay" value="-1">
          <param name="ShowPositionControls" value="0">
          <param name="ShowTracker" value="-1">
          <param name="Volume" value="-480">
          </object>


          3.smi格式

          <OBJECT id=RVOCX classid=clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA width=240
          height=180>
          <param name="_ExtentX" value="6350">
          <param name="_ExtentY" value="4763">
          <param name="AUTOSTART" value="-1">
          <param name="SHUFFLE" value="0">
          <param name="PREFETCH" value="0">
          <param name="NOLABELS" value="-1">
          <param name="SRC" value="rm.rm">
          <param name="CONTROLS" value="ImageWindow">
          <param name="CONSOLE" value="console1">
          <param name="LOOP" value="0">
          <param name="NUMLOOP" value="0">
          <param name="CENTER" value="0">
          <param name="MAINTAINASPECT" value="0">
          <param name="BACKGROUNDCOLOR" value="#000000"><embed src="real.smi" type="audio/x-pn-realaudio-plugin" console="Console1" controls="ImageWindow" height="180" width="240" autostart="true"></OBJECT>

          4.rm格式

          <OBJECT ID=video1 CLASSID="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" HEIGHT=288 WIDTH=352>

          <param name="_ExtentX" value="9313">
          <param name="_ExtentY" value="7620">
          <param name="AUTOSTART" value="0">
          <param name="SHUFFLE" value="0">
          <param name="PREFETCH" value="0">
          <param name="NOLABELS" value="0">
          <param name="SRC" value="rtsp://203.207.131.35/vod/dawan-a.rm";>
          <param name="CONTROLS" value="ImageWindow">
          <param name="CONSOLE" value="Clip1">
          <param name="LOOP" value="0">
          <param name="NUMLOOP" value="0">
          <param name="CENTER" value="0">
          <param name="MAINTAINASPECT" value="0">
          <param name="BACKGROUNDCOLOR" value="#000000"><embed SRC type="audio/x-pn-realaudio-plugin" CONSOLE="Clip1" CONTROLS="ImageWindow" HEIGHT="288" WIDTH="352" AUTOSTART="false">

          </OBJECT>

          5.wmv格式

          <object id="NSPlay" width=200 height=180 classid="CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,5,715" standby="Loading Microsoft Windows Media Player components..." type="application/x-oleobject" align="right" hspace="5">
          <param name="AutoRewind" value=1>
          <param name="FileName" value="xxxxxx.wmv">
          <param name="ShowControls" value="1">
          <param name="ShowPositionControls" value="0">
          <param name="ShowAudioControls" value="1">
          <param name="ShowTracker" value="0">
          <param name="ShowDisplay" value="0">
          <param name="ShowStatusBar" value="0">
          <param name="ShowGotoBar" value="0">
          <param name="ShowCaptioning" value="0">
          <param name="AutoStart" value=1>
          <param name="Volume" value="-2500">
          <param name="AnimationAtStart" value="0">
          <param name="TransparentAtStart" value="0">
          <param name="AllowChangeDisplaySize" value="0">
          <param name="AllowScan" value="0">
          <param name="EnableContextMenu" value="0">
          <param name="ClickToPlay" value="0">
          </object>

          posted @ 2006-05-30 12:51 edsonjava 閱讀(206) | 評論 (0)編輯 收藏
           

          java中提供了io類庫,可以輕松的用java實(shí)現(xiàn)對文件的各種操作。下面就來說一下如何用java來實(shí)現(xiàn)這些操作。
          ?
          新建目錄

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%
          3. //String URL = request.getRequestURI();
          4. String filePath="C:\\測試\\";
          5. filePath=filePath.toString();//中文轉(zhuǎn)換
          6. java.io.File myFilePath=new java.io.File(filePath);
          7. if(!myFilePath.exists())
          8. myFilePath.mkdir();
          9. %>

          新建文件

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%@ page import="java.io.*" %>
          3. <%
          4. String filePath="c:/測試/newFile.txt";
          5. filePath=filePath.toString();
          6. File myFilePath=new File(filePath);
          7. if(!myFilePath.exists())
          8. myFilePath.createNewFile();
          9. FileWriter resultFile=new FileWriter(myFilePath);
          10. PrintWriter myFile=new PrintWriter(resultFile);
          11. String content ="這是測試數(shù)據(jù)";
          12. String strContent = content.toString();
          13. myFile.println(strContent);
          14. resultFile.close();
          15. %>


          刪除文件

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%
          3. String filePath="c://測試//newFile.txt";
          4. filePath=filePath.toString();
          5. java.io.File myDelFile=new java.io.File(filePath);
          6. if(myDelFile.exists())
          7. {??
          8. ??? myDelFile.delete();
          9. ??? out.println(filePath+"刪除成功?。?!");
          10. }
          11. else
          12. {
          13. ??? out.println(filePath+"該文件不存在");
          14. }
          15. %>

          文件拷貝

          1. <%@ page contentType="text/html; charset=gb2312" %>
          2. <%@ page import="java.io.*" %>
          3. <%
          4. int bytesum=0;
          5. int byteread=0;
          6. //file:讀到流中
          7. InputStream inStream=new FileInputStream("c://測試//newFile.txt");
          8. FileOutputStream fs=new FileOutputStream( "c://測試//copyFile.txt");
          9. byte[]? buffer =new? byte[1444];
          10. int length;
          11. while ((byteread=inStream.read(buffer))!=-1)
          12. ?{
          13. ?? out.println("<DT><B>"+byteread+"</B></DT>");
          14. ?? bytesum+=byteread;
          15. ?? out.println(bytesum);
          16. ?? fs.write(buffer,0,byteread);
          17. ?}
          18. inStream.close();
          19. %>

          整個(gè)文件夾拷貝

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%@ page import="java.io.*" %>
          3. <%String url1="C:/aaa";
          4. ? String url2="d:/java/";
          5. ? (new File(url2)).mkdirs();
          6. ?File[] file=(new File(url1)).listFiles();
          7. ?for(int i=0;i<file.length;i++){
          8. ? if(file[i].isFile()){
          9. ?? file[i].toString();
          10. ?? FileInputStream input=new FileInputStream(file[i]);
          11. ?? FileOutputStream output=new FileOutputStream(url2+"/"+(file[i].getName()).toString());
          12. ?? byte[] b=new byte[1024*5];
          13. ??? int len;
          14. ??? while((len=input.read(b))!=-1){
          15. ??? output.write(b,0,len);
          16. ??? }
          17. ??? output.flush();
          18. ??? output.close();
          19. ??? input.close();
          20. ? }
          21. ?}
          22. %>

          文件下載

          1. <%@ page contentType="text/html; charset=gb2312"%>
          2. <%@ page import="java.io.*" %>
          3. <%
          4. ? String fileName = "newFile.txt".toString();
          5. ? //讀到流中
          6. ? InputStream inStream=new FileInputStream("c://測試//newFile.txt");
          7. ? //設(shè)置輸出的格式
          8. ? response.reset();
          9. ? response.setContentType("text/plain");
          10. ? response.addHeader("Content-Disposition","attachment; filename=\"" + fileName + "\"");
          11. ? //循環(huán)取出流中的數(shù)據(jù)
          12. ? byte[] b = new byte[100];
          13. ? int len;
          14. ? ServletOutputStream outStream = response.getOutputStream();
          15. ? while((len=inStream.read(b)) >0)
          16. ? outStream.write(b,0,len);
          17. ? outStream.flush();
          18. ? outStream.close();
          19. ? inStream.close();
          20. %>

          數(shù)據(jù)庫字段中的文件下載

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%@ page import="java.util.*,java.sql.*,java.io.*"%>
          3. <%
          4. ??? String id = request.getParameter("id");
          5. ??? if(id==null)
          6. ??? {?? throw new Exception ("沒有找到圖片");
          7. ??? }
          8. ??? else
          9. ??? {
          10. ?????? try
          11. ?????? {
          12. com.gzrealmap.lib.jdbc.JDBCUtil? SqlBean= com.gzrealmap.lib.jdbc.JDBCUtil.getInstance();
          13. ?????????????? SqlBean.connect();
          14. ?????????????? String sql = "select * from innernews where id = '"+79+"'";
          15. ?????????????? ResultSet rs = SqlBean.queryforUpdate(sql);
          16. ?????????????? rs.next();
          17. ?????????????? //String fileNamedb = rs.getString("imageName");
          18. ?????????????? String file= rs.getString("acc");
          19. ?????????????? //String fileName = new String(fileNamedb.getBytes(),"iso-8859-1");
          20. ?????????????? String fileName = "a.jpg";
          21. ??????????????? response.setHeader("Content-Disposition",? "inline; filename=\"" + fileName + "\"");????
          22. ?????????????? String filter = fileName.substring(fileName.lastIndexOf("."));
          23. ??????????????
          24. ?????????????? if(filter.equals(".txt"))
          25. ?????????????? {
          26. ?????????????????? response.setContentType("text/plain");
          27. ?????????????? }
          28. ?????????????? else if(filter.equals(".doc")||filter.equals(".dot"))
          29. ?????????????? {
          30. ?????????????????? response.setContentType("application/msword");
          31. ?????????????? }
          32. ?????????????? else
          33. ?????????????? {
          34. ???????????????? response.setContentType("image/jpeg;charset=GB2312");
          35. ?????????????? }
          36. ?????????????? ServletOutputStream o = response.getOutputStream();
          37. ?????????????? //o.write(file);
          38. ?????????????? out.println(file);
          39. ?????????????? //o.flush();
          40. ?????????????? //o.close();
          41. ?????????????? SqlBean.disconnect();
          42. ?????? }
          43. ??????? catch(Exception ex)
          44. ?????? {
          45. ?????????? out.println(ex.getMessage());
          46. ?????? }
          47. ??? }??
          48. %>

          把網(wǎng)頁保存成文件

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%@ page import="java.text.*,java.util.*,java.net.*,java.io.*"%>
          3. <%
          4. ?URL stdURL = null;
          5. ?BufferedReader stdIn = null;
          6. ?PrintWriter stdOut = null;
          7. ?try {
          8. ? stdURL = new URL("<a );
          9. ?}
          10. ?catch (MalformedURLException e) {
          11. ?? throw e;
          12. ?}
          13. try {
          14. ??? //將字節(jié)流轉(zhuǎn)變成為字符流
          15. ??? stdIn = new BufferedReader(new InputStreamReader(stdURL.openStream()));
          16. ??? String theFileName = "c://測試//163.html";
          17. ??? stdOut = new PrintWriter(new BufferedWriter(new FileWriter(theFileName.toString())));
          18. ?}
          19. ?catch (IOException e) {
          20. ?}
          21. ?/***把URL指定的頁面以流的形式讀出,寫成指定的文件***/
          22. ?try {
          23. ??? String strHtml = "";
          24. ?? while((strHtml = stdIn.readLine())!=null) {
          25. ?? stdOut.println(strHtml);
          26. ?? }
          27. ?}
          28. ?catch (IOException e) {
          29. ?? throw e;
          30. ?}
          31. ?finally {??
          32. ?? try {
          33. ???? if(stdIn != null)
          34. ?????? stdIn.close();
          35. ???? if(stdOut != null)
          36. ?????? stdOut.close();
          37. ?????? }
          38. ?? catch (Exception e) {
          39. ???? System.out.println(e);
          40. ?? }
          41. ?}
          42. %>

          直接下載網(wǎng)上的文件

          1. <%@ page contentType="text/html;charset=gb2312"%>
          2. <%@ page import="java.io.*"%>
          3. <%@ page import="java.net.*"%>
          4. <%
          5. ? int bytesum=0;
          6. ? int byteread=0;
          7. ? URL url = new URL("<a );
          8. ? URLConnection conn = url.openConnection();
          9. ? InputStream inStream = conn.getInputStream();
          10. ? /**
          11. ? String theFileName = "c:/測試/logo.gif";
          12. ? theFileName = theFileName.toString();
          13. ? File myFilePath=new File(theFileName);
          14. ? if(!myFilePath.exists())
          15. ? myFilePath.createNewFile();
          16. ? **/
          17. ? FileOutputStream fs=new FileOutputStream("c:/測試/logo2.gif");
          18. ? byte[]? buffer =new? byte[1444];
          19. ??? while ((byteread=inStream.read(buffer))!=-1)
          20. ??? {
          21. ?????? out.println("<DT><B>"+byteread+"</B></DT>");
          22. ?????? bytesum+=byteread;
          23. ?????? //System.out.println(bytesum);
          24. ?????? fs.write(buffer,0,byteread);
          25. ???? }
          26. %>

          按行讀文件

          1. <%@ page contentType="text/html; charset=gb2312" %>
          2. <%@ page import="java.io.*" %>
          3. <%
          4. FileReader myFileReader=new FileReader("c:/哈哈.txt");
          5. BufferedReader myBufferedReader=new BufferedReader(myFileReader);
          6. String myString=null;
          7. String resultString=new String();
          8. while((myString=myBufferedReader.readLine())!=null) {
          9. resultString=resultString+myString+"
          10. ";
          11. }
          12. out.println(resultString);
          13. myFileReader.close();
          14. %>

          對word文檔的處理(上傳與下載)

          1. <%@ page contentType="application/msword" %>
          2. <!-- 以上這行設(shè)定本網(wǎng)頁為excel格式的網(wǎng)頁 -->
          3. <%
          4. ?? response.setHeader("Content-disposition","inline; filename=test1.doc"); //線上瀏覽方式
          5. ? // response.setHeader("Content-disposition","attachment; filename=test1.doc");//下載方式
          6. ?? //以上這行設(shè)定傳送到前端瀏覽器時(shí)的檔名為test1.doc
          7. ?? //就是靠這一行,讓前端瀏覽器以為接收到一個(gè)word檔
          8. %>
          9. //然后輸出動(dòng)態(tài)內(nèi)容就可以得到一個(gè)word文檔了

          1,打開:
          1)文件頭上加:

          1. <%@ page? contentType="application/msword"%>?
          2. xml文件里:
          3. <mime-mapping>
          4. ??????? <extension>doc</extension>
          5. ??????? <mime-type>application/msword</mime-type>
          6. </mime-mapping>

          2)可以用js,以下代碼來自引用:

          ]]>




          ?
          2,下載:

          1. <%@ page contentType="text/html;charset=gb2312" import= "java.io.*"%>
          2. <%// 得到文件名字和路徑
          3. ? String filename = "jsp.doc";
          4. ? String filepath = "C:\\";
          5. ? // 設(shè)置響應(yīng)頭和下載保存的文件名
          6. ? response.setContentType("APPLICATION/OCTET-STREAM");
          7. ? response.setHeader("Content-Disposition","attachment; filename=\"" + filename + "\"");
          8. ? // 打開指定文件的流信息
          9. ? java.io.FileInputStream fileInputStream = new java.io.FileInputStream(filepath + filename);
          10. ? //FileOutputStream out? = new FileOutputStream(filepath+"測試\\" + filename);
          11. ? // 寫出流信息
          12. ? int i;
          13. ? while ((i=fileInputStream.read()) != -1) {
          14. ?? out.write(i);
          15. ? }
          16. ? fileInputStream.close();
          17. ? out.close()
          18. ?%>
          posted @ 2006-05-30 12:46 edsonjava 閱讀(370) | 評論 (0)編輯 收藏
           
               摘要: Write an image of a given format ...  閱讀全文
          posted @ 2006-05-30 12:39 edsonjava 閱讀(374) | 評論 (1)編輯 收藏
           
               摘要: Read an image ...  閱讀全文
          posted @ 2006-05-30 10:30 edsonjava 閱讀(352) | 評論 (0)編輯 收藏
           
          ?
          回復(fù)此消息
          前言
          Jive是一個(gè)廣受歡迎的開放的源碼的論壇項(xiàng)目,它有很多值得我們學(xué)習(xí)的地方。這篇文章談的就是Jive緩存機(jī)制的實(shí)現(xiàn),希望對大家有所幫助。
          簡介
          我們知道,在兩個(gè)存取速度差距很大的對象(比如數(shù)據(jù)庫和內(nèi)存)之間,通常要加一個(gè)緩存,來匹配二者的速度。因此,緩存機(jī)制在我們實(shí)際項(xiàng)目中還是經(jīng)常遇到的。同樣Jive也使用緩存來加快貼子的顯示。如果你正試圖編寫一個(gè)類似的東西,不妨研究一下Jive源碼,可能對你大有幫助。
          在Jive2.1.2中,涉及jive的緩存機(jī)制的java類大致可以分為以下四個(gè)部分(為了簡化起見,本文只討論帖子的緩存機(jī)制的實(shí)現(xiàn),用戶名和權(quán)限的存取雖然也用到了的緩存,但其實(shí)現(xiàn)機(jī)制與前者類似,因此不再贅述):
          第一部分:提供HashMap,LinkedListedlist等數(shù)據(jù)結(jié)構(gòu)以便實(shí)現(xiàn)緩存機(jī)制,其中HashMap是JDK提供的,其Key類型為Object。你可以在com.jivesoftware.util包中找到他們,包括的類有Cache類,?LinkedList類,LinkedListNode類和Casheable接口,CacheObject類,CacheableBoolean類,CacheableInt類,CacheableLong類,CacheableLongArray類,CacheableString類,CacheSizes類,CacheTimer類;
          第二部分:提供LongHashMap,LongLinkedListedlist等數(shù)據(jù)結(jié)構(gòu)以便實(shí)現(xiàn)緩存機(jī)制,與第一部分不同的是,它的HashMap是自己編寫的,其Key類型為Long,因此被冠以LongHashMap的名稱。你同樣可以在com.jivesoftware.util包中找到他們,包括的類有LongHashMap類,LongCache類,?LongCacheObject類,
          LongLinkedList類和LongLinkedListNode類;還有第一部分中的Casheable接口,它的各種數(shù)據(jù)類型的實(shí)現(xiàn)以及CacheSizes類和CacheTimer類,也可歸于這部分,它們可看作是第一部分和第二部分的交集;
          第三部分:調(diào)用底層數(shù)據(jù)結(jié)構(gòu)以提供論壇對象的緩存,你可以在com.jivesoftware.forum.database包中找到他們,包括的類主要有DatabaseCacheManager類,DbForumFactory類,DbForum類,DbForumThread類,DbForumMessage?類,DatabaseCache類,F(xiàn)orumCache類,?ForumThreadCache類,F(xiàn)orumMessageCache類;?
          第四部分:向Jsp頁面提供訪問接口,同樣在com.jivesoftware.forum.database包中,包括類有ForumThreadBlockIterator和ForumMessageBlockIterator類,第三部分的DbForum類,DbForumThread類和DbForumMessage?類也可以包括進(jìn)來,實(shí)際上,這三個(gè)類是第三和第四部分聯(lián)系的紐帶,在com.jivesoftware.util包中還有一個(gè)LongList類,它用來將ForumThreadBlockIterator和ForumMessageBlockIterator轉(zhuǎn)化成Long型數(shù)組,因此也應(yīng)算在這部分;
          因此緩存機(jī)制也可以劃分為三層,即第一、二部分的底層數(shù)據(jù)結(jié)構(gòu)、第三部分的中間層和第四部分的上層訪問接口,下面分別討論:
          底層數(shù)據(jù)結(jié)構(gòu)
          ??jive緩存機(jī)制的原理其實(shí)很簡單,就是把所要緩存的對象加到HashMap哈希映射表中,用兩個(gè)LinkedListedlist雙向鏈表分別維持著緩存對象和每個(gè)緩存對象的生命周期,如果一個(gè)緩存對象被訪問到,那么就把它放到鏈表的最前面,然后不定時(shí)的把要緩存對象的對象加入鏈表中,把過期對象刪除,如此反復(fù)。我們比較一下第一和第二部分就可以發(fā)現(xiàn),他們的代碼幾乎完全相同。差別就在第二部分的哈希映射表沒有采用JDK提供的類,而是采用了作者自己編寫的一個(gè)類,他將原來哈希映射表的Key的類型由Object改為Long,這樣做雖然在一定程度上加快了緩存的速度并減小了緩存的大小,但無形之中也減低了程序的穩(wěn)定性和可讀性,因此不推薦大家仿效。值得一提的是,在Jive1.0.2版中,所有Forum,Thread,Message的ID和他們的內(nèi)容的緩存都是用第一部分的Java類實(shí)現(xiàn)的,在升級到后面的版本時(shí),其內(nèi)容采用了第二部分的Java類實(shí)現(xiàn),但其ID仍用第一部分的Java類實(shí)現(xiàn),這也是Jive容易混淆的一個(gè)地方。好了,我們先來看第一部分的Java類實(shí)現(xiàn)。
          我們先來看LinkedListNode類的源碼:
          public?class?LinkedListNode?{
          public?LinkedListNode?previous;
          ????public?LinkedListNode?next;
          ????public?Object?object;
          ????public?long?timestamp;

          public?LinkedListNode(Object?object,?LinkedListNode?next,
          ????????????LinkedListNode?previous)
          ????{
          ????????this.object?=?object;
          ????????this.next?=?next;
          ????????this.previous?=?previous;
          ????}
          public?void?remove()?{
          ????????previous.next?=?next;
          ????????next.previous?=?previous;
          ????}
          public?String?toString()?{
          ????????return?object.toString();
          ????}
          }
          很明顯,這是一個(gè)雙向鏈表的節(jié)點(diǎn)類,previous,next分別記錄前后節(jié)點(diǎn)的指針,object用于記錄所需緩存的對象,timestamp用于記錄當(dāng)前節(jié)點(diǎn)被創(chuàng)建時(shí)的時(shí)間戳。當(dāng)該時(shí)間戳超過該節(jié)點(diǎn)的生存周期時(shí),它就會(huì)被remove()方法刪除掉。就是由LinkedListNode構(gòu)成了LinkedList鏈表,而LinkedList類中只是實(shí)現(xiàn)了getFirst(),getLast(),addFirst(),addLast(),clear()等鏈表的基本方法,沒有其他內(nèi)容。
          再來看Cacheable接口和它的一個(gè)實(shí)現(xiàn)類CacheableInt:

          public?interface?Cacheable?{
          ????public?int?getSize();
          }
          public?class?CacheableInt?implements?Cacheable?{
          ????private?int?intValue;
          ????public?CacheableInt(int?intValue)?{
          ????????this.intValue?=?intValue;
          ????}
          ????public?int?getInt()?{
          ????????return?intValue;
          ????}
          ????public?int?getSize()?{
          ????????return?CacheSizes.sizeOfObject()?+?CacheSizes.sizeOfInt();
          ????}
          }
          從上面的代碼可以看到Cacheable接口只有一個(gè)方法getSize(),它要求繼承類實(shí)現(xiàn)該方法匯報(bào)占用緩存的大小,以便實(shí)施管理。Integer,Boolean,Long,LongArray,String類型都有其對應(yīng)的類,CacheSizes類則把各種類型的長度封裝起來,便于修改和移植。那么為什么CacheableInt.?getSize()得到的是sizeOfObject()+sizeOfInt()呢,聰明的讀者一定想到了,因?yàn)槿魏味祭^承自O(shè)bject,計(jì)算空間時(shí)當(dāng)然也要把它給算上。
          還有一個(gè)CacheObject類,它是緩存的基本元素,我們來看代碼:
          public?final?class?CacheObject?{
          public?Cacheable?object;
          ??????public?int?size;
          ??????public?LinkedListNode?lastAccessedListNode;
          public?LinkedListNode?ageListNode;

          ??????public?CacheObject(Cacheable?object,?int?size)?{
          ????????this.object?=?object;
          ????????this.size?=?size;
          }
          }
          lastAccessedListNode記錄著一個(gè)緩存節(jié)點(diǎn)的Key,是構(gòu)成lastAccessedList鏈表的基本元素,在lastAccessedList鏈表中,經(jīng)常被訪問到的節(jié)點(diǎn)總是在最前面。而ageListNode記錄著緩存節(jié)點(diǎn)的加入時(shí)間,是構(gòu)成ageList鏈表的基本元素,而ageList鏈表則是按時(shí)間先后排序,先加入的節(jié)點(diǎn)總是在最后面。lastAccessedListNode和ageListNode本來可以寫成兩個(gè)類,畢竟lastAccessedListNode并不需要ageListNode的成員變量timestamp,但是為了簡化程序,Jive把他們寫成了一個(gè)類,這也是容易混淆的一個(gè)地方。
          現(xiàn)在來看緩存機(jī)制中最關(guān)鍵的一個(gè)類Cache的部分代碼,主要是add()和get()方法:
          public?class?Cache?implements?Cacheable?{
          protected?static?long?currentTime?=?CacheTimer.currentTime;
          protected?HashMap?cachedObjectsHash;
          protected?LinkedList?lastAccessedList;
          protected?LinkedList?ageList;
          //緩存元素的最大尺寸128kbit,可修改

          protected?int?maxSize?=??128?*?1024;?
          //整個(gè)緩存的大小
          protected?int?size?=?0;
          //緩存元素的最大保存時(shí)間,用Cache(long?maxLifetime)初始化
          protected?long?maxLifetime?=?-1;
          //記錄cache的命中次數(shù)和未命中次數(shù)
          protected?long?cacheHits,?cacheMisses?=?0L;?
          ……
          //向哈希表中添加一個(gè)關(guān)鍵字為Key的緩存對象object
          public?synchronized?void?add(Object?key,?Cacheable?object)?{
          ????????//先把原來的對象remove掉
          ????????remove(key);
          int?objectSize?=?object.getSize();
          ????????//如果對象太大,則不加入緩沖存
          ????????if?(objectSize?>?maxSize?*?.90)?{
          ????????????return;
          ????????}
          ????????size?+=?objectSize;
          ????????//新建一個(gè)緩存對象,并放入哈希表中
          ????????CacheObject?cacheObject?=?new?CacheObject(object,?objectSize);
          ????????cachedObjectsHash.put(key,?cacheObject);
          ????????//?把緩存元素的Key放到lastAccessed?List鏈表的最前面
          ????????LinkedListNode?lastAccessedNode?=?lastAccessedList.addFirst(key);
          ????????cacheObject.lastAccessedListNode?=?lastAccessedNode;
          ????????//把緩存元素的Key放到ageList鏈表的最前面,并記下當(dāng)前時(shí)間
          ????????LinkedListNode?ageNode?=?ageList.addFirst(key);
          ????????ageNode.timestamp?=?System.currentTimeMillis();
          ????????cacheObject.ageListNode?=?ageNode;
          //?在cullCache()中,先調(diào)用deleteExpiredEntries()把過期對象刪掉,如果緩存還是太滿,則掉用remove(lastAccessedList.getLast().object)把lastAccessedList中不常訪問的對象刪掉
          ????????cullCache();
          ????}
          //在哈希表中得到一個(gè)關(guān)鍵字為Key的緩存對象object
          public?synchronized?Cacheable?get(Object?key)?{
          ????????//?清理過期對象
          ????????deleteExpiredEntries();

          ????????CacheObject?cacheObject?=?(CacheObject)cachedObjectsHash.get(key);
          ????????if?(cacheObject?==?null)?{
          ????????????//沒找到則未命中次數(shù)加一
          ????????????cacheMisses++;
          ????????????return?null;
          ????????}

          ????????//找到則命中次數(shù)加一
          ????????cacheHits++;

          ????????//將該緩存對象從lastAccessedList鏈表中取下并插入到
          ????????//鏈表頭部
          ????????cacheObject.lastAccessedListNode.remove();
          ????????lastAccessedList.addFirst(cacheObject.lastAccessedListNode);

          ????????return?cacheObject.object;
          ????}
          到這里第一部分的Java類實(shí)現(xiàn)就說完了,正如上文提到的那樣,第二部分的Java類實(shí)現(xiàn)與第一部分基本上沒有什么差別,因此就不再贅述。下面給出第二部分的類圖,以供讀者參考。
          [img]http://www.javaresearch.org/members/{tomjava}
          中間層
          ?????中間層是聯(lián)系上層訪問接口和低層數(shù)據(jù)結(jié)構(gòu)的紐帶。它的主要功能就是根據(jù)ID(對應(yīng)于數(shù)據(jù)庫中的編號)到緩存中去找相應(yīng)的對象,如果緩存中有該對象就直接得到,沒有則去讀數(shù)據(jù)庫生成一個(gè)新的對象,再把該對象放入緩存中,以便下次訪問時(shí)能直接得到。下面是相關(guān)類的類圖:
          [img]http://www.javaresearch.org/members/{tomjava}
          (注:Forum表示論壇,Thread表示論壇貼子的線索,Message表示論壇貼子,它們的關(guān)系是這樣的?:Forum包括數(shù)條Thread,Thread包括數(shù)條Message。)
          由上圖可見,DbForum類,DbForumThread類和DbForumMessage?類的實(shí)例對象都包含一個(gè)?DbForumFactory類的實(shí)例對象factory。DbForum,DbForumThread和DbForumMessage被DbForumFactory生產(chǎn)出來,同時(shí)他們也通過DbForumFactory來訪問緩存。而在DbForumFactory中則包含一個(gè)DatabaseCacheManager類的實(shí)例對象cacheManager,它負(fù)責(zé)管理所有的緩存對象,如圖,這些緩存對象就是ForumCache類,?ForumThreadCache類和ForumMessageCache類的實(shí)例。ForumCache類,?ForumThreadCache類和ForumMessageCache類繼承自同一個(gè)抽象類DatabaseCache,而在DatabaseCache類中,有一個(gè)LongCache型的成員變量cache,就這樣,中間層就和低層的數(shù)據(jù)結(jié)構(gòu)結(jié)合起來了。
          我們以thread線索對象的獲得為例來說明中間層是如何運(yùn)作的,請看代碼摘要:
          DbForum.java
          public?class?DbForum?implements?Forum,?Cacheable?{
          ????。。。?。。。
          public?ForumThread?getThread(long?threadID)
          ????????????throws?ForumThreadNotFoundException
          ????{
          ????????return?factory.getThread(threadID,?this);
          ????}
          。。。?。。。
          }

          DbForumFactory.java
          public?class?DbForumFactory?extends?ForumFactory?{
          ????。。。?。。。
          protected?DbForumThread?getThread(long?threadID,?DbForum?forum)?throws
          ????????????ForumThreadNotFoundException
          ????{
          ????????DbForumThread?thread?=?cacheManager.threadCache.get(threadID);
          ????????return?thread;
          }
          。。。?。。。
          }

          ForumThreadCache.java
          public?class?ForumThreadCache?extends?DatabaseCache?{
          ????。。。?。。。
          public?DbForumThread?get(long?threadID)
          ????????????throws?ForumThreadNotFoundException
          { //緩存中尋找以threadID為編號的DbForumThread對象
          DbForumThread?thread?=?(DbForumThread)cache.get(threadID);
          ????????if?(thread?==?null)?{
                //如果在緩存中找不到該對象
          ????????????//新建一個(gè)以threadID為編號的DbForumThread對象
          thread?=?new?DbForumThread(threadID,?factory);
          //將新建對象加入緩存
          ????????????cache.add(threadID,?thread);
          ????????}
          ????????return?thread;
          }
          ???。。。?。。。
          }

          DbForumThread.java
          public?class?DbForumThread?implements?ForumThread,?Cacheable?{
          ???。。。?。。。
          protected?DbForumThread(long?id,?DbForumFactory?factory)
          ????????????throws?ForumThreadNotFoundException
          ????{
          ????????this.id?=?id;
          ????????this.factory?=?factory;
          //讀取數(shù)據(jù)庫,其中id對應(yīng)數(shù)據(jù)庫中的jiveThreadProp表中的threadID字段
          ????????loadFromDb();
          ????????isReadyToSave?=?true;
          }
          ???。。。?。。。
          }
          ???從上面的代碼我們可以看到,當(dāng)我們調(diào)用DbForum類?的getThread(long?threadID)方法去獲得一個(gè)編號為threadID的線索對象時(shí),我們實(shí)際上調(diào)用的是DbForumFactory類中的getThread(long?threadID,?DbForum?forum)方法,而它則是調(diào)用ForumThreadCache類的方法來完成任務(wù)的。那么ForumThreadCache類里get(long?threadID)方法有做了什么呢?代碼已經(jīng)很清楚了,就是根據(jù)threadID到緩存中去找相應(yīng)的線索對象,如果緩存中有該對象就直接得到,沒有則新建一個(gè)DbForumThread對象,再把該對象放入緩存中??吹竭@里,有點(diǎn)讓人奇怪,好象程序中根本沒有連接數(shù)據(jù)庫的語句。再看DbForumThread類的代碼,終于恍然大悟,原來Jive在新建一個(gè)DbForumThread對象就已經(jīng)用loadFromDb()方法把數(shù)據(jù)讀出來了;另一方面,如果在緩存中找了DbForumThread對象,程序根本就不會(huì)新建DbForumThread對象,因而就好象沒有數(shù)據(jù)庫的操作,這實(shí)際上就是我們通過緩存機(jī)制所要達(dá)到的目的。
          ????Message帖子對象的獲得與Thread對象的獲得類似,因此就不再重復(fù)了。從上面我們可以看到,只要我們得到了論壇線索的編號threadID,我們就可以得到對應(yīng)的線索對象,不管它是從緩存中來,還是從數(shù)據(jù)庫中來。那么threadID是如何從Jsp頁面?zhèn)鞯街虚g層的呢?讓我們來看上層訪問接口的運(yùn)行機(jī)制吧。
          上層訪問接口
          ????上層訪問接口的主要功能連接Jsp頁面和中間層,換句話說,就是把Jsp頁面中要調(diào)用的Thread、Message對象的ID傳遞到中間層。下面給出訪問Thread的相關(guān)類的類圖(訪問Message機(jī)制類似,故省略)。其中的forum.jsp是顯示論壇內(nèi)容的頁面,在這里,我們把forum.jsp看成是一個(gè)特殊的類,它里面有一個(gè)ForumThreadIterator類的實(shí)例變量threads和DbForum類的實(shí)例變量forum,故它和ForumThreadIterator類及DbForum類的關(guān)系應(yīng)是關(guān)聯(lián)關(guān)系。
          [img]http://www.javaresearch.org/members/{tomjava}
          先來看forum.jsp和DbForum?類的部分代碼:
          forum.jsp
          <%
          //?ResultFilter結(jié)果過濾類
          ResultFilter?filter?=?new?ResultFilter();
          ????filter.setStartIndex(start);
          ????filter.setNumResults(range);
          //調(diào)用Dbforum的threads()方法,獲得ForumThreadIterator對象實(shí)例
          ForumThreadIterator?threads?=?forum.threads(filter);
          。。。?。。。
          while?(threads.hasNext())?{
          ????????//對thead進(jìn)行遍歷
          ????????ForumThread?thread?=?(ForumThread)threads.next();
          ????????//得到thread的ID
          ????????long?threadID?=?thread.getID();
          ????????//得到線索的根帖子rootMessage
          ????????ForumMessage?rootMessage?=?thread.getRootMessage();
          ????????//得到帖子主題和作者等信息
          ????????String?subject?=?rootMessage.getSubject();
          ????????User?author?=?rootMessage.getUser();
          。。。?。。。
          }
          %>
          DbForum.java
          public?class?DbForum?implements?Forum,?Cacheable?{
          。。。?。。。
          public?ForumThreadIterator?threads(ResultFilter?resultFilter)?{
          ????//生成SQL語句
          ????????String?query?=?getThreadListSQL(resultFilter,?false);
          ????????//得到threadID塊
          long?[]?threadBlock?=?getThreadBlock(query.toString(),
          ?resultFilter.getStartIndex());
          ????????。。。?。。。
          ????????//返回ForumThreadBlockIterator對象
          ????????return?new?ForumThreadBlockIterator(threadBlock,?query.toString(),
          ????????????????startIndex,?endIndex,?this.id,?factory);
          }
          protected?long[]?getThreadBlock(String?query,?int?startIndex)?{
          ????????int?blockID?=?startIndex?/?THREAD_BLOCK_SIZE;
          ????????int?blockStart?=?blockID?*?THREAD_BLOCK_SIZE;??
          ????????String?key?=?query?+?blockID;?????
          ?//根據(jù)Key的值到緩存中取得ThreadID的數(shù)組
          ????????CacheableLongArray?longArray?=?
          (CacheableLongArray)threadListCache.get(key);
          ????????//在緩存中則返回
          ????????if?(longArray?!=?null)?{
          ????????????long?[]?threads?=?longArray.getLongArray();
          ????????????return?threads;
          ????????}
          ????????//?否則到數(shù)據(jù)庫中取ThreadID的塊,以數(shù)組形式返回
          ????????else?{
          ????????????LongList?threadsList?=?new?LongList(THREAD_BLOCK_SIZE);
          ????????????Connection?con?=?null;
          ????????????Statement?stmt?=?null;
          ????????????。。。數(shù)據(jù)庫操作?。。。
          ????????????}
          ????????????long?[]?threads?=?threadsList.toArray();
          ????????????//將?ThreadID的塊加入緩存
          threadListCache.add(key,?new?CacheableLongArray(threads));
          ????????????return?threads;
          ????????}
          ?????}
          。。。?。。。
          }
          在forum.jsp中有一個(gè)ResultFilter類的實(shí)例resultFilter,它給出頁面顯示Thread的起始位置和數(shù)量,它作為參數(shù)傳入forum.threads()中,用于構(gòu)造相關(guān)的SQL語句。當(dāng)調(diào)用forum.threads(filter)時(shí),程序?qū)⑸傻腟QL語句傳入到getThreadBlock()方法中去得到一個(gè)threadID的塊,也就是一組threadID。之所以要讀threadID塊,是因?yàn)轱@示論壇時(shí)并不是顯示一條線索就行了,而是一下顯示十幾條,這樣做可以避免反復(fù)讀數(shù)據(jù)庫,再說threadID不是thread對象,并不怎么占空間。
          應(yīng)該說,使用了塊以后,減輕了數(shù)據(jù)庫的訪問量,因而論壇的效率有了很大的提高。然而好戲還在后頭,Jive又把塊放入了緩存中。在getThreadBlock()方法里,Jive用Cache類的實(shí)例對象threadListCache來緩存threadID塊,而關(guān)鍵字就是SQL語句加上blockID,也就是說,主要SQL語句和blockID相同,就可以在緩存中取出相同的threadID塊。當(dāng)然,緩存中找不到,還是要到數(shù)據(jù)庫中讀出來加入緩存的。這樣論壇的效率又得到了進(jìn)一步的提升。
          ForumThreadBlockIterator類繼承自ForumThreadIterator抽象類,而ForumThreadIterator類又實(shí)現(xiàn)了Iterator接口,因此得到ForumThreadBlockIterator的實(shí)例對象threads后,就可以在用threads.next()方法對它進(jìn)行編歷了。ForumThreadBlockIterator類的代碼想都可以想得到,就是逐個(gè)讀取ThreadID,然后根據(jù)ThreadID返回Thread對象,由此上層訪問接口就和中間層銜接起來了。
          小結(jié)
          Jive的緩存機(jī)制值得我們學(xué)習(xí)的地方有很多,比如讀取線索時(shí)不是讀一條而是讀一個(gè)block;顯示線索的起始位置和數(shù)量用專門的一個(gè)類來管理,動(dòng)態(tài)生成SQL語句;用一個(gè)專門的類來負(fù)責(zé)管理緩存;把論壇緩存對象的功能抽象出來形成一個(gè)緩存的抽象類DatabaseCache,讓它去跟低層數(shù)據(jù)結(jié)構(gòu)聯(lián)系起來。這些都體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)原則即提高軟件的可維護(hù)性和可復(fù)用性。
          同時(shí),Jive也告訴我們,要想編好程序,只懂條件語句和循環(huán)語句可不行;必須選擇好數(shù)據(jù)結(jié)構(gòu),掌握好面向?qū)ο蟮脑O(shè)計(jì)原則,熟悉設(shè)計(jì)模式思想方法,這樣才能編寫出強(qiáng)壯高效的代碼。
          posted @ 2006-05-23 00:23 edsonjava 閱讀(420) | 評論 (0)編輯 收藏
          僅列出標(biāo)題
          共7頁: 上一頁 1 2 3 4 5 6 7 
           
          主站蜘蛛池模板: 伊金霍洛旗| 阜平县| 鲜城| 林州市| 文登市| 井冈山市| 平山县| 搜索| 互助| 富源县| 托克逊县| 阿勒泰市| 瑞金市| 二连浩特市| 依安县| 巴南区| 遵义县| 梁河县| 沐川县| 璧山县| 铜川市| 琼中| 容城县| 武胜县| 苏尼特左旗| 平定县| 改则县| 莱阳市| 旌德县| 屏东市| 阳春市| 开化县| 任丘市| 庆城县| 沽源县| 邮箱| 嵊泗县| 古丈县| 三原县| 平湖市| 南溪县|