亚洲成年看片在线观看,亚洲国产精品福利片在线观看 ,精品国产亚洲一区二区在线观看http://www2.blogjava.net/jackstudio/category/9250.htmlzh-cnWed, 28 Feb 2007 19:49:01 GMTWed, 28 Feb 2007 19:49:01 GMT60各種排序算法java實現 http://www.tkk7.com/jackstudio/archive/2006/12/15/87971.htmljackstudiojackstudioFri, 15 Dec 2006 08:06:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/12/15/87971.htmlhttp://www.tkk7.com/jackstudio/comments/87971.htmlhttp://www.tkk7.com/jackstudio/archive/2006/12/15/87971.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/87971.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/87971.html閱讀全文

jackstudio 2006-12-15 16:06 發表評論
]]>
struts,ajax亂碼解決方案 http://www.tkk7.com/jackstudio/archive/2006/12/10/86629.htmljackstudiojackstudioSat, 09 Dec 2006 18:38:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/12/10/86629.htmlhttp://www.tkk7.com/jackstudio/comments/86629.htmlhttp://www.tkk7.com/jackstudio/archive/2006/12/10/86629.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/86629.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/86629.html 轉載:http://www.tkk7.com/errorfun/archive/2006/12/09/86584.html
作者:errorfun


亂碼問題好像跟我們中國程序員特別有緣,一直困擾著我們,從開始的JSP亂碼問題,STRUTS亂碼問題,到現在的AJAX亂碼問題,無一不是搞得許多程序員焦頭爛額的,整天罵XXX產品對中文支持不了,UTF-8無法使用中文啊什么的,其實這里面被罵的產品中其實99%以上是對中文支持非常好的,而出現亂碼的原因只是因為自身對國際化支持以及文件編碼等信息的認識不知造成的。要知道一個產品那么流行,怎么可能對中文支持不了呢,下面就開始一一幫大家解決這些問題。


1
、編碼
????? --
想要解決好中文問題,對編碼肯定是不能一概不懂了,編碼是解決中文亂碼問題的根本。
???? ?
編碼比較常用的有: UTF-8 GBK GB2312 ISO-8859-1 ,除了 iso-8859-1 之外的其它三個編碼都能很好的支持中文,但它們都兼容 ISO-8859-1 的編碼(就是說無論編碼怎么改變,只要是 ISO-8859-1 中的字符,永遠不會出現亂碼)。
?????
這四種編碼中, GB2312 是中國規定的漢字編碼,也可以說是簡體中文的字符集編碼 ; GBK GB2312 的擴展 , 除了兼容 GB2312 外,它還能顯示繁體中文,還有日文的假名 ; UTF-8 雖然也支持中文,但卻 GB 碼不兼容(編碼值不同) UTF-8 使用的是可變長的 UNICODE 編碼,編碼可能是 1 16 進制(即 ISO-8859-1 中的字符,其編碼也是相同的)也有可能是 2 位或 3 位的 16 進制。 UTF-8 的優點是: 1 CPU 字節順序無關 , 可以在不同平臺之間交流。 2 、容錯能力高 , 任何一個字節損壞后 , 最多只會導致一個編碼碼位損失 , 不會鏈鎖錯誤 ( GB 碼錯一個字節就會整行亂碼 ) ,所以在國際化處理中基本都是建議使用 UTF-8 作為編碼。

2、文件的編碼
????? --雖然說只要設置了正確的編碼就可以使字符正確顯示了,但如果忽略了文件保存時的編碼的話,那可是會讓你走進迷霧中的。
????? 文件編碼最常使用的有兩種:ANSI和UTF-8,光看名字估計你都可以猜到了,ANSI就是我們保存文件時使用的默認編碼,而UTF-8則需自己設置。對于編碼的改變,我使用的工具是NOTEPAD和ECLIPSE,NOTEPAD使用最簡單,只要打開文件后在另存為中選擇相應的編碼就行了,而且它對編碼的支持非常好;而在ECLIPSE中,只要稍微設置一下就行了,打開首選項,然后選擇:常規->內容類型(ContentType),在右邊選中你想改變保存編碼的文件類型,然后在下方的缺省編碼中改變其值,最后點擊更新(UPDATE)按鈕即可。



而在其它的編輯器中,默認保存的內容都是GB2312或者GBK(NOTEPAD中對應ANSI).而根據前面所說的UTF-8和GBK,GB2312等的編碼值是不同的這一點,可以知道,如果文件使用了UTF-8,那么字符編碼就必須使用UTF-8,否則編碼值的不同就可能造成亂碼。而這也就是為什么那么多的人使用了UTF-8編碼后還會產生亂碼的根本原因。(JS和JSP都是這個道理)

3、JSP,STRUTS等的中文亂碼解決方案
?????其實解決的方法只有一個:

?request.setCharacterEncoding(encoding);

???方法只有一種,但處理方式就多種多樣了,初學者會在JSP頁面上直接使用,而有經驗的程序員會使用過濾器。而現在所要說的方法也是過濾器。這里以統一使用UTF-8作為編碼作為例子說明。具體過程就不多說了,網上有很多教程。偷懶一點的,到TOMCAT中復制就行了。在TOMCAT的目錄下的\webapps\jsp-examples\WEB-INF\classes\filters\找到SetCharacterEncodingFilter.java 這個類,放到你的程序中并配置好映射路徑。配置好后基本上你的亂碼問題就解決了。但要映射路徑中需要注意的就是不能使用 '*'

?? < filter-mapping >
????
< filter-name > Set?Character?Encoding </ filter-name >
????
< servlet-name > * </ servlet-name >
??
</ filter-mapping >

像上面這樣配置的話(可能也是網上大多教程的做法,想當年也是害苦了我),可能你只有JSP的亂碼解決了,要解決STRUTS的亂碼需要映射 *.do 或者 servletActionName。然后在初始化參數中設置encoding的值就行了。

< init-param >
??????
< param-name > encoding </ param-name >
??????
< param-value > UTF-8 </ param-value >
</ init-param >

當然,最重要的是要記得根據前面所說的方法,改變你所使用的編輯器保存文件的編碼要與使用的字符編碼一致。
而在JSP內容中,還是使用如網上教程所說的那種技倆,在所有頁面的頁首加入:

<% @?page?language = "java"?contentType = " text / html;?charset = UTF - 8 "
????pageEncoding
= "UTF - 8 " %>

至此,相信JSP,ACTION都不太可能出現亂碼了。

4、資源文件的亂碼解決方案
????? 資源文件誰都知道是國際化支持不可或缺的一部分,如果資源文件都出現亂碼了那還了得?其實資源文件的亂碼是很好解決的,其原因也是因為使用了UTF-8做為JSP編碼后,沒有相應地改變資源文件的文件編碼造成的,所以只要對資源文件保存的編碼進行更正后,亂碼問題也就解決了。當然,你的中文要使用 native2ascii 命令進行正確的轉換。

5、調用JS時,JS內容亂碼的解決方案。
???? 其實JS的亂碼還是跟文件的編碼有關系的,如果JS中有中文的話,那JS文件保存的編碼就必須跟調用此JS的頁面編碼相同,否則,你的所有中文都要從JSP頁面傳給JS才會顯示正常。可以看出對于調用JS出現的亂碼是最容易解決的(也是建立在前面的辛苦之下的)。

6、AJAX提交數據亂碼,返回數據亂碼的解決方案
???? 隨著AJAX的流行,亂碼問題也開始困擾著許多剛開始使用它的程序員,幸好我之前對JSP亂碼有過一點研究,在遇到AJAX后,并沒有給我帶來多大的困擾,在此將我的一些心得共享給大家。
???? 萬變不離其宗,AJAX的亂碼問題自然跟編碼有關了,其實很多人跟我一樣想到了對文件編碼進行設置,并且在接數據時設置了requet的編碼,在返回的數據時設置了response的編碼一切都以為會很順利,可是這一切都是徒勞無功的,討厭的亂碼再一次出現在你眼前。在你試了N多種方法,包括JS自身的escape,unescape方法后,你發現亂碼仍然猖狂地出現在屏幕上。
??? 其實在試過這N多方法后,很多人都沒發現,解決的方法其實很簡單,而且其答案就在我們之前處理的JSP亂碼之中。讓我們先看一下AJAX的經典請求代碼

xmlhttp.open(?"post",?url,?async?);
xmlhttp.setRequestHeader(?
"Content-Type",?"text/html"
?);
xmlhttp.send(?params?);

通過前面的說明,不知道你現在看出端倪了沒有。不知道是受了網上教程的影響還是其它方面影響,setRequestHeader并是萬年不變的,也沒人想過去改它,而問題就正好出在這個地方。回想一個JSP頁面內容的編碼設置,其中有這么一節:
contentType="text/html;?charset=UTF-8"

現在知道問題了吧,所以我們要把第二句代碼改為:
xmlhttp.setRequestHeader(?"Content-Type",?"text/html;charset=UTF-8"?);

最后別忘了在返回數據時也設置上:
response.setContentType(?"text/xml"?);
response.setCharacterEncoding(?
"UTF-8"?);

是不是很簡單,一點都不麻煩呢?
如果要問為什么的話,其實我們可以把xmlhttp看成是一個臨時頁面,它由瀏覽器動態生成,主要作用是在后臺獲得請求的數據(可以看成是一個高級的iframe)。所以對于普通頁面設置的編碼,對它也要同樣設置。而在servlet中返回數據為什么要設置contentType和encoding其道理也是一樣的。眾所周知,jsp的最后形態就是servlet,而jsp頁首設置的那個內容其實也就是讓生成的servlet中生成這么兩句話:
response.setContentType(?"text/html"?);
response.setCharacterEncoding(?
"UTF-8"?);

而pageEncoding則是跟jvm說明了這個頁面的內容要使用什么編碼保存(這跟之后生成的CLASS有關系)。所以在servlet設置response的編碼也是理所當然的了。

一口氣把自己一年以來遇到的亂碼問題和解決的方案寫出來了,希望對你有所幫助。


jackstudio 2006-12-10 02:38 發表評論
]]>
spring有三種啟動方式,使用ContextLoaderServlet,ContextLoaderListener和ContextLoaderPlugIn.http://www.tkk7.com/jackstudio/archive/2006/11/09/80060.htmljackstudiojackstudioThu, 09 Nov 2006 02:40:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/11/09/80060.htmlhttp://www.tkk7.com/jackstudio/comments/80060.htmlhttp://www.tkk7.com/jackstudio/archive/2006/11/09/80060.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/80060.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/80060.htmlspring有三種啟動方式,使用ContextLoaderServlet,ContextLoaderListener和ContextLoaderPlugIn.
看一下ContextLoaderListener的源碼,這是一個ServletContextListener
/**
? * Initialize the root web application context.
? */
?public void contextInitialized(ServletContextEvent event) {
? this.contextLoader = createContextLoader();
? this.contextLoader.initWebApplicationContext(event.getServletContext());
?}
?
? /**
? * Create the ContextLoader to use. Can be overridden in subclasses.
? * @return the new ContextLoader
? */
?protected ContextLoader createContextLoader() {
? return new ContextLoader();
?}

?contextLoader的源碼
?public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
?? throws BeansException {

? long startTime = System.currentTimeMillis();
? if (logger.isInfoEnabled()) {
?? logger.info("Root WebApplicationContext: initialization started");
? }
? servletContext.log("Loading Spring root WebApplicationContext");

? try {
?? // Determine parent for root web application context, if any.
?? ApplicationContext parent = loadParentContext(servletContext);

?? WebApplicationContext wac = createWebApplicationContext(servletContext, parent);
?? servletContext.setAttribute(
???? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);

?? if (logger.isInfoEnabled()) {
??? logger.info("Using context class [" + wac.getClass().getName() +
????? "] for root WebApplicationContext");
?? }
?? if (logger.isDebugEnabled()) {
??? logger.debug("Published root WebApplicationContext [" + wac +
????? "] as ServletContext attribute with name [" +
????? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
?? }

?? if (logger.isInfoEnabled()) {
??? long elapsedTime = System.currentTimeMillis() - startTime;
??? logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
?? }

?? return wac;
? }
? catch (RuntimeException ex) {
?? logger.error("Context initialization failed", ex);
?? servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
?? throw ex;
? }
? catch (Error err) {
?? logger.error("Context initialization failed", err);
?? servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
?? throw err;
? }
?}
?注意WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,這里面放了WebApplicationContext,需要使用時從ServletContext取出
?可以使用WebApplicationContextUtils得到WebApplicationContext
?public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
? Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
? if (attr == null) {
?? return null;
? }
? if (attr instanceof RuntimeException) {
?? throw (RuntimeException) attr;
? }
? if (attr instanceof Error) {
?? throw (Error) attr;
? }
? if (!(attr instanceof WebApplicationContext)) {
?? throw new IllegalStateException("Root context attribute is not of type WebApplicationContext: " + attr);
? }
? return (WebApplicationContext) attr;
?}
?關鍵的問題在于struts如何啟動的spring的,ContextLoaderPlugIn的源碼
?
?// Publish the context as a servlet context attribute.
? String attrName = getServletContextAttributeName();
? getServletContext().setAttribute(attrName, wac);
?
?public String getServletContextAttributeName() {
? return SERVLET_CONTEXT_PREFIX + getModulePrefix();
?}
?不同加載的Key竟然不同,原因就是WebApplicationContext放在那里的問題,可spring調用的時候會根據WebApplicationContext里面定義的那個名字去找的,問題出在這里


?在struts-config.xml中配置
??? <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
????? <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" />
??? </plug-in>

??? <controller>
??????? <set-property property="processorClass" value="org.springframework.web.struts.DelegatingRequestProcessor" />
??? </controller>


?原理是這樣的,Struts雖然只能有一個ActionServlet實例,但是對于不同的子應用分別能有自己的RequestProcessor實例每個RequestProcessor實例分別對應不同的struts配置文件。
?? 子應用的ProcessorClass類必須重寫一般就是繼承RequestProcessor類,然后再其配置文件的controller元素中的<processorClass>屬性中作出修改。那么當
? getRequestProcessor(getModuleConfig(request)).process(request,response);就能根據request選擇相應的moduleconfig,再根據其<processorClass>屬性選擇相應的RequestProcessor子類來處理相應的請求了。

?



jackstudio 2006-11-09 10:40 發表評論
]]>
使用ServletContextListener在服務器啟動和關閉時創建和關閉緩存http://www.tkk7.com/jackstudio/archive/2006/11/09/80058.htmljackstudiojackstudioThu, 09 Nov 2006 02:39:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/11/09/80058.htmlhttp://www.tkk7.com/jackstudio/comments/80058.htmlhttp://www.tkk7.com/jackstudio/archive/2006/11/09/80058.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/80058.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/80058.html

ServletContext 被 Servlet 程序用來與 Web 容器通信。例如寫日志,轉發請求。每一個 Web 應用程序含有一個Context,被Web應用內的各個程序共享。因為Context可以用來保存資源并且共享,所以我所知道的 ServletContext 的最大應用是Web緩存----把不經常更改的內容讀入內存,所以服務器響應請求的時候就不需要進行慢速的磁盤I/O了。

ServletContext 被 Servlet 程序用來與 Web 容器通信。例如寫日志,轉發請求。每一個 Web 應用程序含有一個Context,被Web應用內的各個程序共享。因為Context可以用來保存資源并且共享,所以我所知道的 ServletContext 的最大應用是Web緩存----把不經常更改的內容讀入內存,所以服務器響應請求的時候就不需要進行慢速的磁盤I/O了。

ServletContextListener 是 ServletContext 的監聽者,如果 ServletContext 發生變化,如服務器啟動時 ServletContext 被創建,服務器關閉時 ServletContext 將要被銷毀。

在JSP文件中,application 是 ServletContext 的實例,由JSP容器默認創建。Servlet 中調用 getServletContext()方法得到 ServletContext 的實例。

我們使用緩存的思路大概是:

  1. 服務器啟動時,ServletContextListener 的 contextInitialized()方法被調用,所以在里面創建好緩存。可以從文件中或者從數據庫中讀取取緩存內容生成類,用 ervletContext.setAttribute()方法將緩存類保存在 ServletContext 的實例中。

  2. 程序使用 ServletContext.getAttribute()讀取緩存。如果是 JSP,使用a pplication.getAttribute()。如果是 Servlet,使用 getServletContext().getAttribute()。如果緩存發生變化(如訪問計數),你可以同時更改緩存和文件/數據庫。或者你等 變化積累到一定程序再保存,也可以在下一步保存。

  3. 服務器將要關閉時,ServletContextListener 的 contextDestroyed()方法被調用,所以在里面保存緩存的更改。將更改后的緩存保存回文件或者數據庫,更新原來的內容。

import User; //my own class
import DatabaseManager; // my own class
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;

public class MyContextListener

implements ServletContextListener {
private ServletContext context = null;

public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();
User user = DatabaseManager.getUserById(1);
context.setAttribute("user1", user);
}

public void contextDestroyed(ServletContextEvent event) {
User user = (User)context.getAttribute("user1");
DatabaseManager.updateUserData(user);
this.context = null;
}
}

布署 ServletContextListener

你實現(implements)了 ServletContextListener 編譯后,把它放在正確的WEB-INF/classes目錄下,更改WEB-INF目錄下的 web.xml文件,在web-app節點里添加

<listener>
<listener-class>MyServletContextListener</listener-class>
</listener>
?來自:


jackstudio 2006-11-09 10:39 發表評論
]]>
EJB輕松進階http://www.tkk7.com/jackstudio/archive/2006/10/23/76764.htmljackstudiojackstudioMon, 23 Oct 2006 07:24:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/10/23/76764.htmlhttp://www.tkk7.com/jackstudio/comments/76764.htmlhttp://www.tkk7.com/jackstudio/archive/2006/10/23/76764.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/76764.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/76764.htmlhttp://dev.21tx.com/java/ejb/

編寫第一個EJB應用程序

   搞清了基本的分布式對象應用程序機理,下面我們就來實地做一個簡單的EJB應用程序,一步一步找著做,你會發現——它真的不難!

   EJB中的Beans有兩種,一種是會話Bean(SessionBean),一種是實體Bean(EntityBean)。其中,SessionBean又分為有狀態(Stateful)和無狀態(Stateless)兩種,EntityBean又分為容器管理(Container Managed)和自管理(Bean Managed)兩種。我們要做的第一個EJB應用程序是:寫一個無狀態會話Bean(Stateless SessionBean)。

這個程序的功能是: 實現一個遠程加密、解密演示系統,用戶把一段明文發到服務器端,服務器端執行一定的加密算法(按先后順序倒排)得到密文,然后把加密完成后的密文發到客戶端顯示給用戶;用戶還可發一段加密后的密文到服務器端,服務器端執行一定的解密算法(倒排)得到明文,然后回傳顯示給用戶。

注: 這里使用的是Windows平臺,并且假定JDK已經裝好,并且認為你至少是編過一個Java程序的程序員。

第一步 下載、安裝J2EE開發工具箱

   編寫EJB應用程序必須下載相關的工具箱才行,作為學習試驗之用,不須采用很高檔的應用服務器(比如:WebLogic、WebSphere等),只需采用SUN公司提供的免費開發包就可以了,下載地址為:ftp://202.116.77.69/development/Java/j2sdkee1.2/j2sdkee-img_java ejb/2_1-win.exe。

   下載后執行這個應用程序,即可完成J2EESDK的本地安裝(假定安裝在C:\j2sdkee1.3目錄)。安裝之后還不能立刻用,需要把C:\j2sdkee1.3\lib\j2ee.jar加到系統的ClassPath變量中去,裝過JDK的朋友對此肯定不會陌生。做完這些后,最終系統的ClassPath應該至少有.;C:\j2sdk1.4.0-beta3\lib\tools.jar; C:\j2sdk1.4.0-beta3\lib\dt.jar;C:\j2sdkee1.3\lib\j2ee.jar這幾項。

   然后,把C:\j2sdkee1.3\bin目錄加到系統的Path變量中,也就是說,系統的Path變量至少應該有%PATH%;C:\j2sdkee1.3\bin;C:\j2sdk1.4.0-beta3\bin這幾項。

以上兩步其實和配置J2SE的方法類似,配過JDK的朋友一定不陌生。

第二步 建立應用程序目錄結構

   如你所知的,Java程序中目錄結構是很重要的,因為Java中的包(package)是與目錄相關的,同時,目錄結構不同,程序打包生成(jar)的結構也不同,所以必須引起重視。

   我們編寫的第一個EJB應用程序的目錄結構如圖二所示,由上可見,所有的java程序都放在securitybeans目錄下(它們都屬于一個名為securitybeans的package)。客戶代碼主要由JSP和html文件組成:musecurityjsp.html文件為靜態網頁,主要用于顯示系統的首頁,提供用戶輸入明文/密文的界面,并負責把用戶輸入的內容提交給下一個頁面(SecuriryProcessPage.jsp);SecurityProcessPage.jsp文件為用JSP(Java Server Pages)編寫的動態網頁,主要用于生成EJB對象實例,并向EJB對象發送加密/解密請求,并在頁面上顯示加密/解密結果供用戶瀏覽。


?編寫EJB代碼

   由前述的目錄結構可知,EJB代碼包括三個Java文件。

   1、Security.java是一個接口,它定義了基本的加密、解密調用接口。注意,由于Security接口可生成EJB對象,所以它必須繼承自EJBObject接口。其源代碼如下:

文件“Security.java”

package securitybeans;

import java.rmi.RemoteException;

import javax.ejb.EJBObject;

public interface Security extends EJBObject

{

public String encrypt( String strSource ) throws RemoteException;

public String decrypt( String strTarget ) throws RemoteException;

}/* Security */

   2、SecurityHome接口可生成EJBHome對象,它負責直接與客戶打交道,接收客戶的請求,返回處理結果。在EJB規范中,SecurityHome必須繼承自EJBHome接口。其源代碼如下:

文件“SecurityHome.java”

package securitybeans;

import java.rmi.RemoteException;

import javax.ejb.EJBHome;

import javax.ejb.CreateException;

public interface SecurityHome extends EJBHome

{

Security create() throws CreateException, RemoteException;

}/* EJBHome */

   3、SecurityBean類才是真正做“正事”的類,它負責對SecurityHome對象傳來的字符串執行加密、解密算法,將得到的結果返回給SecurityHome對象。它是一個Stateless SessionBean,按照EJB規范,必須實現SessionBean接口。其源代碼如下:

文件“ScurityBean.java”

package securitybeans;

import java.rmi.RemoteException;

import javax.ejb.SessionBean;

import javax.ejb.SessionContext;

public class SecurityBean implements SessionBean

{

public String encrypt( String strSource )

{

String strTarget = "";

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

{

strTarget += strSource.charAt( i );

}//for


return strTarget;

}//encrypt()


public String decrypt( String strTarget )

{

String strSource = "";


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

{

strSource += strTarget.charAt( i );

}//for


return strSource;

}//decrypt()


public void ejbActivate() {}//ejbActivate()

public void ejbRemove() {}//ejbRemove()

public void ejbPassivate() {}//ejbPassivate()

public void setSessionContext( SessionContext sc ) {}//setSessionContext()

public void ejbCreate() {}//ejbCreate()

public void ejbLoad() {}//ejbLoad()

public void ejbStore() {}//ejbStore()

}/* SecurityBean */

   SecurityBean中的ejbActivate()、ejbPassivate()等方法都是SessionBean接口中的方法,由于本程序中這里不需要有實際內容,因此直接實現它就可以了。


編寫客戶代碼

   便完了EJB代碼,下面我們來寫客戶代碼。

   1、mysecurityJSP.html文件用于顯示一個靜態的網頁,它提供了用戶錄入明文/密文的界面,使用戶能夠錄入自己的內容然后提交給服務器端。其源代碼如下:

文件mysecurityjsp.html

< HTML >
< HEAD >
< TITLE >EJB示例:數據加密、解密演示系統< /TITLE >
< /HEAD >
< BODY BACKGROUND="bg.gif" >

< CENTER >

< H1 >數據加密解密演示系統< IMG SRC="duke.gif" >< /H1 >
< BR >< BR >< BR >
< FORM METHOD="GET" ACTION="SecurityJSPAlias" >
< TABLE WIDTH="700" HEIGHT="300" BORDER="1" >
< TR >
< TD ALIGN="CENTER" >
< H2 >——加密請求窗——< /H2 >
< P >
請輸入明文:
< P >
< INPUT TYPE="TEXT" NAME="SOURCECONTENT" >< /INPUT >
< P >
< INPUT TYPE="SUBMIT" VALUE=" 提 交 " >
< INPUT TYPE="RESET" VALUE=" 重 置 " >
< /TD >
< TD ALIGN="CENTER" >
< H2 >——解密請求窗——< /H2 >
< P >
請輸入密文:
< P >
< INPUT TYPE="TEXT" NAME="TARGETCONTENT" >< /INPUT >
< P >
< INPUT TYPE="SUBMIT" VALUE=" 提 交 " >
< INPUT TYPE="RESET" VALUE=" 重 置 " >
< /TD >
< /TR >
< /TABLE >
< /FORM >

< /CENTER >

< /BODY >
< /HTML >

   2、SecurityProcessPage.jsp文件是用JSP編寫的動態網頁,它用于處理mysecurityjsp.html提交過來的內容,并查找、生成EJBHome對象,發送加密/解密請求,并將結果傳回客戶端。其源代碼如下:

文件“SecurityProcessPage.jsp”

< %@ page language="Java" info="數據加密解密信息處理系統" % >
< %@ page import="java.rmi.*" % >
< %@ page import="javax.naming.*" % >
< %@ page import="javax.rmi.PortableRemoteObject" % >
< %@ page import="securitybeans.*" % >

< HTML >
< HEAD >
< TITLE >EJB示例:數據加密、解密演示系統< /TITLE >
< /HEAD >
< %
SecurityHome shMain = null;
Try
{
shMain = ( SecurityHome )PortableRemoteObject.narrow( new InitialContext().lookup( "mysecurity" ), SecurityHome.class );
}//try
catch( NamingException ne )
{
ne.printStackTrace();
}//catch
Security security = shMain.create();
% >
< BODY BACKGROUND="bg.gif" >
< CENTER >
< H1 >數據加密解密演示系統< IMG SRC="duke.gif" >< /H1 >< BR >< BR >< BR >
< TABLE WIDTH="700" HEIGHT="300" BORDER="1" >
< TR >
< TD ALIGN="CENTER" >
< %
if ( request.getParameter( "SOURCECONTENT" ) != null )
{
% >
加密生成的密文為:< BR >
< %= security.encrypt( request.getParameter( "SOURCECONTENT" ) ) % >
< %
}//if
% >
< /TD >
< TD ALIGN="CENTER" >
< %
if ( request.getParameter( "TARGETCONTENT" ) != null )
{
% >
解密生成的明文為:< BR >
< %= security.encrypt( request.getParameter( "TARGETCONTENT" ) ) % >
< %
}//if
% >
< /TD >
< /TR >
< /TABLE >
< /CENTER >
< /BODY >
< /HTML >


運行第一個EJB應用程序

   一個完整的EJB應用程序已經寫完了,但是事情還遠沒有完結。要使一個EJB應用程序能夠運行,還有很多事情要做。并且,可能這些事情的工作量并不比編程序本身小多少。

第一步 編譯EJB代碼

   html和JSP代碼是不需編譯的,但securitybeans目錄下的三個.Java文件必須編譯成.class文件才可運行。由于三個Java文件屬于一個包,所以要進行聯編。

第二步 啟動J2EE服務器

   打開一個DOS Shell窗口,鍵入j2ee –verbose,稍候片刻,當屏幕出現提示“J2EE server startup complete”時,表示j2eesdk自帶的J2EE服務器啟動成功了。

第三步 打開配置工具

   打開一個DOS Shell窗口(如果你現每次打開一個新的DOS Shell窗口麻煩,可以在前一步中鍵入start j2ee –verbose,即可自動彈出一個新的窗口,而原窗口不變),鍵入deploytool,稍候片刻,即可啟動j2eesdk自帶的配置工具。Deploytool的啟動畫面如圖三所示。


圖三 deploytool的啟動畫面

新建一個Application


圖四 新建一個Application


   點擊deploytool的File菜單->New->Application,在彈出的對話框中選中SecurityApp所在的目錄,并在Display Name中輸入任意一個你想在界面上看到的這個應用程序的名稱(比如:SecurityApp)。

第五步 新建一個EntERPrise Bean

   下面就將進入比較關鍵的部分!

   點擊deploytool的File菜單->New->Enterprise Bean,將彈出一個New Enterprise Bean Wizard。點擊Next按鈕略過第一個界面,在第二個界面中輸入JAR Display Name為“SecurityJar”,并點擊Edit按鈕,在彈出的對話框中將securitybeans目錄下的三個.Java編譯后生成的.class文件加入到SecurityJar的內容中去,如圖五所示。


圖五 將.class文件添加到SecurityJar中


   點擊Next到第三個界面,注意:

1. 選中Session為Stateless(缺省為Stateful);

2. 輸入Enterprise Bean Name為SecurityBean;

3. 選擇Enterprise Bean Class為securitybeans.SecurityBean;

4. 選擇Remote Home Interface為securitybeans.SecurityHome;

5. 選擇Remote Interface為securitybeans.Security。

   至此關鍵的步驟就完成了,以下幾個界面你大可以放心的“Next”了。至最后一個界面點擊Finish按鈕,即完成了一個Enterprise Bean的添加工作。


新建一個Web Component

這個步驟與上一步驟類似


   點擊deploytool的File菜單->New->Web Component,將彈出一個New Web Component Wizard。點擊Next按鈕略過第一個界面,在第二個界面中輸入WAR Display Name為“SecurityWar”,并點擊Edit按鈕,在彈出的對話框中將ClientCode目錄下的幾個客戶代碼文件加入到SecurityWar的內容中去,如圖六所示。


圖六 將ClientCode目錄下的文件添加到SecurityJar中


   點擊Next進入第三個界面,選擇the type of web component you are creating為JSP。點擊Next進入第四個界面,注意:

1、 選中JSP FileName為SecurityProcessPage.jsp;

2、 輸入Web Component Name為SecurityProcessPage。

   兩次點擊Next按鈕進入第五個界面,點擊Add按鈕,給該Web Component添加一個別名為SecurityAlias。

   至此主要的步驟就完成了,以下幾個界面只需放心點擊Next按鈕即可,至最后一個界面,點擊Finish按鈕,即完成了一個Web Component的添加工作。

第七步 修改JNDI和RootContext

   添加完了兩個主要的組件之后,還要修改兩個配置,才能最后完成EJB的配置。


圖七 SecurityApp的JNDI Names標簽頁的設置


   在deploytool主界面左邊的樹形結構中點擊SecurityApp節點,主界面的右邊就會顯示出四個標簽頁。在這四個標簽頁中,JNDI Names標簽頁需加上mysecurity為JNDI Name,如圖七所示;WebContext標簽頁中需加上SecurityRoot為SecurityWar的ContextRoot,如圖八所示。


圖八 SecurityApp的Web Context標簽頁的設置


第八步 校驗J2EE應用程序

   完成以上七個步驟后,整個EJB的配置工作就基本完成了,下面只需簡單兩個步驟就大功告成,不過也要做好功虧一簣的準備!

   在deploytool主界面左邊的樹形結構中點擊SecurityApp節點,再點擊deploytool的Tools菜單->Verifier…菜單項,在彈出窗口中點擊OK按鈕,deploytool將自動對EJB應用程序進行測試校驗,檢查有沒有配置錯誤。稍候片刻,如果提示“There were no failed tests.”,則恭喜你大功告成。如果提示有錯,則需要返回去仔細重新檢查一步步配置,看看有沒有地方疏漏了。配置錯誤可是很容易出的喲,你要有思想準備。



發布J2EE應用程序

   如果通過了第八步,則第九步就完全是例行公事了。

   點擊deploytool的Tools菜單->Deploy…菜單項,會彈出一個發布向導對話框窗口,只管放心點擊Next到最后一個界面,至最后一個界面點擊“Finish”按鈕,等待Deployment Progress至最后完成,如圖九所示,就徹底搞定了!


圖九 發布完成后的Deployment Progress


第十步 欣賞程序運行效果

   接下來打開一個瀏覽器窗口,輸入http://localhost:8000/SecurityRoot,就可以欣賞到你第一個EJB應用程序的運行效果了。

   第一個頁面如圖十所示,顯示的是一個數據錄入頁面,用戶可錄入一些想要加密/解密的內容,點擊提交按鈕就可到下一個頁面。

   第二個頁面如圖十一所示,顯示的是對用戶請求內容的加密/解密處理結果。


圖十 運行效果第一個頁面(加密/解密請求窗)


圖十一 運行效果第二個頁面(加密/解密結果顯示頁)


   萬事開頭難,有了第一個EJB應用程序運行通過的體驗,以后就好辦了。希望本文能為你開個好頭!



jackstudio 2006-10-23 15:24 發表評論
]]>
JavaMail 深入淺出http://www.tkk7.com/jackstudio/archive/2006/10/23/76762.htmljackstudiojackstudioMon, 23 Oct 2006 07:10:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/10/23/76762.htmlhttp://www.tkk7.com/jackstudio/comments/76762.htmlhttp://www.tkk7.com/jackstudio/archive/2006/10/23/76762.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/76762.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/76762.html閱讀全文

jackstudio 2006-10-23 15:10 發表評論
]]>
淺論taglib設計 http://www.tkk7.com/jackstudio/archive/2006/09/09/68675.htmljackstudiojackstudioSat, 09 Sep 2006 02:47:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/09/09/68675.htmlhttp://www.tkk7.com/jackstudio/comments/68675.htmlhttp://www.tkk7.com/jackstudio/archive/2006/09/09/68675.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/68675.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/68675.html 淺論taglib設計

[概述]

Taglib是JSP比較高級的技術。做為JSP開發人員來講,不了解taglib是可以接受的。因為JSP的風格或者JAVA的風格就是一種簡潔的美。如果技術太過復雜或者繁瑣,就會在技術的汪洋中失去自我。

但是,當我們的項目變得越來越大,或者團隊有了一些技術積累之后,很自然就會有將我們的開發工作提高一個層次的需要。當我們面對一些非常類似的界面或者程序單元的時候,我們會想到把這樣的工作成果直接用于下一個項目。這樣的問題可以由taglib來解決。

到此還沒有真正說明一下taglib是什么。只要你從事過JSP的開發工作,你就已經使用過taglib了。只不過是在不知不覺中使用的。你一定不會忘記 <jsp:include />標記。實際上這就是一個taglib。Taglib直譯做標記庫,是JSP定義給開發人員可以使用自行定義的標記體系。也就是說,開發人員可以在JSP中使用自己定義的特殊標記。而該標記可以用作特定的用途。比如顯示一個每個頁都需要的公司版權信息。就可以不用復制粘貼相同的代碼到每個頁去了。

但是taglib可以完成的工作遠遠不止這些。由于每個自定義標記一定是一個完全的JAVA類,我們可以定義非常豐富的一組行為,并且可以通過自定義的attribute來控制它。

[實例]

我習慣用實例來說明問題。大家也許都對用戶會話狀態的檢查不陌生。當用戶登錄到系統后,我們希望自動保持用戶的登錄狀態。而這個過程在每個需要認證用戶才能訪問的程序單元都需要實現。通常我們需要訪問預定義的session服務器變量,當這個變量不滿足某值時即判定改用戶為非法訪問或者會話狀態丟失。

我們來看一下使用taglib如何實現。我們需要編寫一個僅處理該邏輯的標記。實現的最簡單的邏輯:檢查用戶狀態session值,不滿足某值時即將用戶轉向一個預先設置的報錯頁。

以下是源碼(CheckSessionTag.java):
(省略了細節)

public?class?CheckSessionTag?extends?TagSupport
{
????public?
int
?doEndTag()
????{
????????
try

????????{
????????????String?member_id?
= ?(String)?pageContext.getSession().getAttribute( " member_id " );
????????????
if (member_id? == ? null ? || ?member_id.equals( ""
))
????????????{
????????????????pageContext.forward(
" /home/check_session_fail.jsp "
);
????????????}
????????}
????????
catch
(Exception?e)
????????{
????????????
// ?報告異常過程省略.

????????}
????????
return
?EVAL_PAGE;
????}
}



[分析]

在以上源碼中,我們在使tag自動檢查用戶session變量中的"member_id"值,如果該值為空,則立即判定用戶沒有訪問權限,則立即將流程導向一個預先設定的報錯頁:/home/check_session_fail.jsp.

類CheckSessionTag派生自:TagSupport(javax.servlet.jsp.tagext.TagSupport). 是一個從JAVA 1.3就開始支持的類庫,位于servlet.jar包。java文檔給出的描述是:

A base class for defining new tag handlers implementing Tag. The TagSupport class is a utility class intended to be used as the base class for new tag handlers. The TagSupport class implements the Tag and IterationTag interfaces and adds additional convenience methods including getter methods for the properties in Tag. TagSupport has one static method that is included to facilitate coordination among cooperating tags. Many tag handlers will extend TagSupport and only redefine a few methods.
(該類為所有taglib的基類。該類定義了實現標記的一系列接口。)

在實例CheckSessionTag類中,我們僅僅重寫了doEndTag方法。沒有向其容器:jsp頁輸出任何東西。但是該類在實際應用中是切實可行的。

以下是在一個成品項目中的某jsp中截取的片斷:
<logic:checkSession />

當我們直接使用輸入url的方式訪問本頁時,我們被立即帶到了報告:用戶會話狀態丟失或者未經登錄的頁。
這就省卻了我們習以為常的一項工作:以前我們必須復制相同的scriplet到每個jsp頁。(實際上,也可以使用類似intercept filter的模式來處理此需求)。這使我們的開發工作變得reusable, flexiable, 和extendable。可以想象,如果我們想改變檢查session的邏輯,則可以僅僅通過改變CheckSessionTag內部的邏輯就可以通盤改變。并且我們可以通過給logic:checkSession標記加上類似target=admin的attribute來限定只有管理員才可以訪問的區域。這就是形成組件化開發的基本過程。

如何實施呢?


[實施過程]

我們需要做一系列工作來將taglib引入我們的工程。

web.xml
為了使jsp解析器可以識別我們的taglib必須將其配置在web.xml內。web.xml位于/WEB-INF目錄內。
使用特定語法來配置我們的taglib:
web.xml(片斷)

< web-app >

????
< taglib >
????????
< taglib-uri > /WEB-INF/logic.tld </ taglib-uri >
????????
< taglib-location > /WEB-INF/logic.tld </ taglib-location >
????
</ taglib >

< web-app >

該語法告訴容器到什么地方去尋找所有logic:開頭的tag.

tld是taglib defination的縮寫。即taglib定義。該文件定義了我們使用的標記,Java類如何加載,并且該標記如何工作。讓我們來看一段實際的tld:
logic.tld(片斷)

<? xml?version="1.0"?encoding="ISO-8859-1" ?>
<! DOCTYPE?taglib
?????PUBLIC?"-//Sun?Microsystems,?Inc.//DTD?JSP?Tag?Library?1.2/EN"
?????"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"
>


< taglib >
????
< tlib-version > 1.0 </ tlib-version >
????
< jsp-version > 1.2 </ jsp-version >
????
< short-name > logic </ short-name >
????
< uri > /taglibs/logic </ uri >

????
< tag >
???????
< name > checkSession </ name >
???????
< tag-class > mbajob.common.tags.logic.CheckSessionTag </ tag-class >
???????
< body-content > empty </ body-content >
????
</ tag >


我們注意到taglib標記內.
1.?short-name: 標記的prefix名。
2.?uri: 識別該taglib的名稱。

tag標記:
1.?name: 標記名(prefix:之后)
2.?tag-class:類名(包含包名)
3.?body-content: 標記內容模式,如果該標記沒有內容則為empty.

將logic.tld放置在/WEB-INF下,此時確保編譯好的CheckSessionTag類可以被容器訪問到。即可完成配置。必須注意的是,不同的jsp容器的配置可能有差別。本文的配置是基于Resin 2.1.11

[應用]

建立一個jsp頁。在源碼的開頭加入如下的預編譯指令:(page)
<%@ taglib prefix="logic" uri="/WEB-INF/logic.tld" %>

此指令告訴編譯器到哪里去尋找所有以logic:開頭的標記的定義。

接下來在任意位置加入標記:<logic:checkSession />即可以工作了。當標記被實例化后,即自動執行doEndTag過程,檢查session服務器變量值,之后將頁過程跳轉。


[深入一些:attribute]

有時候我們希望可以對標記進行一些定制。依舊拿checkSession做例:現在我們要限制兩類用戶訪問系統:某
些部分僅允許具有管理員權限的用戶訪問。這樣我們設想可以在<logic:checkSession target=admin />進行進一步定義。這需要在CheckSessionTag類中增加一些額外的邏輯。檢查的過程很簡單,取決于你的安全系統的分析,但是,我們寫了target attribute如何是類可以得到該數據,這是一個關鍵的問題。

為了實現對tag增加可用的attribute, 需要做如下工作:
1.?為類增加相應的成員及相應讀寫器:
CheckSessionTag.java(片斷):?

public?class?CheckSessionTag?extends?TagSupport
{
?????private?String?target;

?????public?
void
?setTarget(String?t)
?????{
????????
this .target? =
?t;
?????}

?????public?String?getTarget()
?????{
????????
return ? this
.target;
?????}

????public?
int
?doEndTag()
????{
????????
????}


2.?更改logic.tld:

.

????
< tag >

???????
< name > checkSession </ name >
???????
< tag-class > mbajob.common.tags.logic.CheckSessionTag </ tag-class >
???????
< body-content > empty </ body-content >
???????
< attribute >
??????????
< name > title </ name >
??????????
< required > true </ required >
???????
</ attribute >
????
</ tag >

為tag標記增加arrtibute節點,語法如下:

name: attribute名
required: 是否為必須的attribute

幸運的是,jsp內置地將attribute解釋為java類的成員,我們無需顯式地獲取該值,即可直接使用。也就是說,我們只要在tag內指定了target=admin, 那么,CheckSessionTag在活著的時候就自動獲取該值,可以在邏輯中直接使用。

這樣,我們就可以給tag增加任意的attribute.


[入門以后]

到此為止,我么就可以寫一些類似的簡單的tag了。根據不同的需求,完成不同的邏輯。當我們開發一個新的tag的時候,我們在logic.tld里增加一個tag子標記。設置好相應的類型。如果需要,我們可以把我們已經寫好的tag們完全的移植到第二個項目中使用,僅僅做很少的更改。而更改也僅僅限于對java源代碼。

在我和我的團隊的實際經驗中,taglib最多的應用還是在設計一系列特殊的UI. 例如類似于選擇省市多級行政區域的選擇器。為了放置在HTML中嵌入過多scriplet和腳本,我們的做法通常是將其寫在組裝好的tag里;為了形成整個應用一致的外觀,我們設計了一套用于組裝頁構圖的框架;為了向jsp輸出集合數據,我們設計了可以綁定數據的呈現器。經過很長一個時期的工作,我們發現我們的項目中jsp頁內僅有很少的html, 而完全是有taglib組成的。最終,我們的taglib按照layout, logic, element, form分類,已經形成了比較大的規模。我們甚至完成了apache的struts框架完成的一部分工作。甚至做得更靈活。所有這些工作中積累的思想甚至影響到我在.NET平臺下的技術思路。

為了不使篇幅太長,我不準備在本文再做深入的探索。僅僅介紹taglib入門級的一些東西。有時間的話,可能會再次寫一些高級一些的taglib的設計方法。


[與ASP.NET Web Custom Control]

不能說taglib與ASP.NET Web Custom Control有什么可比性。但是我習慣將二者放到一起看。因為因為在某些實際項目中,我確實從二者之間找到一些共性。甚至有時候創作一些組件的時候實現是完全相同的。
1.?二者都定義了當標記輸出開始標記和結束標記時的過程。
2.?二者都可以跨應用使用。
3.?可以使用相同的HTML和腳本。

但比較起來,ASP.NET Web Custom Control更高級一些。可以在容器中直接以對象的形式訪問。并且可以定義方法,事件。意即可以完全控制一個控件。

而taglib同樣有優點,例如可以嵌套使用,開發成本低等。最關鍵的是,taglib具有做為java產品的精細,小巧和活潑。他們分別是有著不同風格的優秀技術。

參考文檔
taglib最佳實踐(IBM developerWorks中文站)
http://www-900.ibm.com/developerWorks/cn/java/j-jsp07233/



jackstudio 2006-09-09 10:47 發表評論
]]>
應用OSCache提升J2EE系統運行性能 http://www.tkk7.com/jackstudio/archive/2006/09/09/68664.htmljackstudiojackstudioSat, 09 Sep 2006 02:06:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/09/09/68664.htmlhttp://www.tkk7.com/jackstudio/comments/68664.htmlhttp://www.tkk7.com/jackstudio/archive/2006/09/09/68664.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/68664.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/68664.html作者簡介

肖菁,軟件工程師,IBM developerWorks/Bea dev2dev/sun 技術開發者撰稿人,主要研究J2EE、web services以及他們在websphere、weblogic平臺上的實現,擁有IBM的 Developing With Websphere Studio證書。您可以通過guilaida@163.com和作者取得聯系,或者查看作者的主頁獲取更多信息。

文章摘要


Cache是一種用于提高系統響應速度、改善系統運行性能的技術。尤其是在Web應用中,通過緩存頁面的輸出結果,可以很顯著的改善系統運行性能。本文中作者給大家介紹一個實現J2EE框架中Web應用層緩存功能的開放源代碼項目----OSCache。通過應用OSCache,我們不但可以實現通常的Cache功能,還能夠改善系統的穩定性。

1?面臨的問題


1.1?需要處理的特殊動態內容


在信息系統建設過程中我們通常會遇到這樣的問題:

1. 基礎數據的變更問題

信息系統中需要處理的基礎數據的內容短時間內是不會發生變化的,但是在一個相對長一些的時間里,它卻可能是動態增加或者減少的。

舉個例子:電子商務中關于送貨區域的定義,可能短時間內不會發生變化,但是隨著電子商務企業業務的擴大,系統中需要處理的送貨區域就可能增加。所以我們的系統中不得不在每次向客戶展示送貨區域信息的時候都和數據庫(假設送貨區域信息保存在數據庫中,這也是通常采用的處理方法)進行交互。

2. 統計報表(不僅限于統計報表)的問題

一般來說,統計報表是一個周期性的工作,可能是半個月、一個月或者更長的時間才會需要更新一次,然而統計報表通常是圖形顯示或者是生成pdf、word、excel等格式的文件,這些圖形內容、文件的生成通常需要消耗很多的系統資源,給系統運行造成很大的負擔。

1.2 問題的共同點


通過比較分析,不難發現這兩類問題有一些共同點:

1、被處理的內容短時間不變,所以短時間內可以作為靜態內容進行處理

2、在一個不太長的時間內,被處理的內容可能或者必定產生變化,所以必須將他們作為動態內容進行處理

3、在合理的時間區段內可以忽略被處理內容變化后帶來的影響

4、對這些內容的處理動作比較消耗系統性能,影響系統響應時間

1.3 解決方法


緩存技術可以幫助我們很好的解決這個問題:

1、緩存信息

當上述的基礎數據或者統計報表第一次被訪問時,被處理的內容被當作動態信息,基礎數庫從數據庫中獲得,統計報表也會被生成符合要求的圖形、文件,然后這些信息都會被放入緩存信息中。

2、響應信息由緩存提供

當上述的基礎數據或者統計報表繼續被訪問時,系統將會首先檢查緩存信息中是否有對應的內容和我們設定的緩存規則,如果符合緩存信息存在而且符合緩存規則,給出的響應將來自于緩存信息,如果沒有或者緩存信息已經不符合設定的要求,系統將重復上一步的動作。

很顯然,上面的步驟2中,多數情況下,當用戶請求到達時,被處理的內容將來自于緩存,所以大大的減少了與數據庫的交互,或者不再需要為每個請求都生成一次報表圖形或者文件,這部分工作的減少對于降低系統性能消耗、提高系統穩定性和并發處理能力是非常有益的。

2?OSCache簡介


OSCache是OpenSymphony組織提供的一個J2EE架構中Web應用層的緩存技術實現組件,它的出現解決了我們面臨的問題。 OSCache目前最新的穩定版本是2.0,本文中的例子都是基于這個版本的,如果大家運行例子的過程中發生問題,請首先確認是否采用了正確的軟件版本。

2.1?主要特征


1. 兼容多種支持JSP的web服務器

已經通過兼容測試的web服務器包括OrionServer (1.4.0或者以上版本) 、Macromedia JRun (3.0或者以上版本) 、BEA Weblogic (7.x或者以上版本) 、IBM Websphere (5.0版本)、Silverstream (3.7.4版本)、Caucho Resin (1.2.3或者以上版本)、Tomcat (4.0或者以上版本) ,其他支持servlet2.3、jsp1.2的web服務器應該都是完全兼容OSCache的。

2. 可選的緩存區

你可以使用內存、硬盤空間、同時使用內存和硬盤或者提供自己的其他資源(需要自己提供適配器)作為緩存區。

  • 使用內存作為緩存區將可以提供更好的性能
  • 使用硬盤作為緩存區可以在服務器重起后迅速恢復緩存內容
  • 同時使用內存和硬盤作為緩存區則可以減少對內存的占用

3. 靈活的緩存系統

OSCache支持對部分頁面內容或者對頁面級的響應內容進行緩存,編程者可以根據不同的需求、不同的環境選擇不同的緩存級別。

4. 容錯

在一般的web應用中,如果某個頁面需要和數據庫打交道,而當客戶請求到達時,web應用和數據庫之間無法進行交互,那么將返回給用戶"系統出錯"或者類似的提示信息,如果使用了OSCache的話,你可以使用緩存提供給用戶,給自己贏得維護系統或者采取其他補救的時間。

其它特性還包括對集群的支持、緩存主動刷新等特性,大家可以參考OpenSymphony網站上的其他資源獲取更多的信息。

3?OSCache組件的安裝


OSCache是一個基于web應用的組件,他的安裝工作主要是對web應用進行配置,大概的步驟如下:

1. 下載、解壓縮OSCache

請到OSCache的主頁http://www.opensymphony.com/oscache/download.html下載Oscache的最新版本,作者下載的是OSCache的最新穩定版本2.0。

將下載后的。Zip文件解壓縮到c:\oscache(后面的章節中將使用%OSCache_Home%來表示這個目錄)目錄下

2. 新建立一個web應用

3. 將主要組件%OSCache_Home%\oscache.jar放入WEB-INF\lib目錄

4. commons-logging.jar、commons-collections.jar的處理

  • OSCache組件用Jakarta Commons Logging來處理日志信息,所以需要commons-logging.jar的支持,請將%OSCache_Home%\lib\core\commons-logging.jar放入classpath(通常意味著將這個文件放入WEB-INF\lib目錄)
  • 如果使用JDK1.3,請將%OSCache_Home%\lib\core\commons-collections.jar放入classpath,如果使用JDK1.4或者以上版本,則不需要了

5. 將oscache.properties、oscache.tld放入WEB-INF\class目錄

  • %OSCache_Home%\oscache.properties包含了對OSCache運行特征值的設置信息
  • %OSCache_Home%\oscache.tld包含了OSCache提供的標簽庫的定義內容

6. 修改web.xml文件

在web.xml文件中增加下面的內容,增加對OSCache提供的taglib的支持:

<taglib>
<taglib-uri>oscache</taglib-uri>
<taglib-location>/WEB-INF/classes/ oscache.tld</taglib-location>
</taglib> 

4?開始使用OSCache中的緩存組件


OSCache中按照緩存范圍的不同分為兩種不同的方式:一種是緩存JSP頁面中部分或者全部內容,一種是基于整個頁面文件的緩存。

4.1?JSP部分內容緩存


4.1.1?Cache-OSCache提供的緩存標簽


這是OSCache提供的標簽庫中最重要的一個標簽,包括在標簽中的內容將應用緩存機制進行處理,處理的方式將取決于編程者對cache標簽屬性的設置。

第一次請求到達時,標簽中的內容被處理并且緩存起來,當下一個請求到達時,緩存系統會檢查這部分內容的緩存是否已經失效,主要是以下幾項:

  • 1. 緩存時間超過了cache標簽設置的time或者duration屬性規定的超時時間
  • 2. cron屬性規定的時間比緩存信息的開始時間更晚
  • 3. 標簽中緩存的內容在緩存后又被重新刷新過
  • 4. 其他緩存超期設定

如果符合上面四項中的任何一項,被緩存的內容視為已經失效,這時被緩存的內容將被重新處理并且返回處理過后的信息,如果被緩存的內容沒有失效,那么返回給用戶的將是緩存中的信息。

cache標簽的屬性說明:

key - 標識緩存內容的關鍵詞。在指定的作用范圍內必須是唯一的。默認的key是被訪問頁面的URI和后面的請求字符串。

你可以在同一個頁面中使用很多cache標簽而不指定他的key屬性,這種情況下系統使用該頁面的URI和后面的請求字符串,另外再自動給這些key增加一個索引值來區分這些緩存內容。但是不推薦采用這樣的方式。

scope - 緩存發生作用的范圍,可以是application或者session

time - 緩存內容的時間段,單位是秒,默認是3600秒,也就是一個小時,如果設定一個負值,那么這部分被緩存的內容將永遠不過期。

duration - 指定緩存內容失效的時間,是相對time的另一個選擇,可以使用簡單日期格式或者符合USO-8601的日期格式。如:duration='PT5M' duration='5s'等

refresh - false 或者true。

如果refresh屬性設置為true,不管其他的屬性是否符合條件,這部分被緩存的內容都將被更新,這給編程者一種選擇,決定什么時候必須刷新。

mode - 如果編程者不希望被緩存的內容增加到給用戶的響應中,可以設置mode屬性為"silent"

其它可用的屬性還包括:cron 、groups、language、refreshpolicyclass、refreshpolicyparam。

上面的這些屬性可以單獨使用,也可以根據需要組合使用,下面的例子將講解這些常用屬性的使用方式。

4.1.2?Cache標簽實例分析:


1. 最簡單的cache標簽用法

使用默認的關鍵字來標識cache內容,超時時間是默認的3600秒

<cache:cache>
<%
//自己的JSP代碼內容
%>
</cache:cache> 

2. 用自己指定的字符串標識緩存內容,并且設定作用范圍為session。

<cache:cache key="foobar" scope="session">
<%
//自己的JSP代碼內容
%>
</cache:cache> 

3.動態設定key值,使用自己指定的time屬性設定緩存內容的超時時間,使用動態refresh值決定是否強制內容刷新。

因為OSCache使用key值來標識緩存內容,使用相同的key值將會被認為使用相同的的緩存內容,所以使用動態的key值可以自由的根據不同的角色、不同的要求決定使用不同的緩存內容。

<cache:cache key="<%= product.getId() %>" time="1800" refresh="<%= needRefresh %>">
<%
//自己的JSP代碼內容
%>
</cache:cache> 

4. 設置time屬性為負數使緩存內容永不過期

<cache:cache time="-1">
<%
//自己的JSP代碼內容
%>

5. 使用duration屬性設置超期時間

<cache:cache  duration='PT5M'>
<%
//自己的JSP代碼內容
%>

6. 使用mode屬性使被緩存的內容不加入給客戶的響應中

<cache:cache  mode='silent'>
<%
//自己的JSP代碼內容
%>

4.2?用CashFilter實現頁面級緩存


在OSCache組件中提供了一個CacheFilter用于實現頁面級的緩存,主要用于對web應用中的某些動態頁面進行緩存,尤其是那些需要生成pdf格式文件/報表、圖片文件等的頁面,不僅減少了數據庫的交互、減少數據庫服務器的壓力,而且對于減少web服務器的性能消耗有很顯著的效果。

這種功能的實現是通過在web.xml中進行配置來決定緩存哪一個或者一組頁面,而且還可以設置緩存的相關屬性,這種基于配置文件的實現方式對于J2EE來說應該是一種標準的實現方式了。

[注] 只有客戶訪問時返回http頭信息中代碼為200(也就是訪問已經成功)的頁面信息才能夠被緩存

1. 緩存單個文件

修改web.xml,增加如下內容,確定對/testContent.jsp頁面進行緩存。

<filter>
      <filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-對/testContent.jsp頁面內容進行緩存-->
      <url-pattern>/testContent.jsp</url-pattern>
</filter-mapping>

2. 緩存URL pattern

修改web.xml,增加如下內容,確定對*.jsp頁面進行緩存。

<filter>
      <filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-對所有jsp頁面內容進行緩存-->
      <url-pattern>*.jsp</url-pattern>
</filter-mapping>

3. 自己設定緩存屬性

在頁面級緩存的情況下,可以通過設置CacheFilter的初始屬性來決定緩存的一些特性:time屬性設置緩存的時間段,默認為3600秒,可以根據自己的需要只有的設置,而scope屬性設置,默認為application,可選項包括application、session

<filter>
      <filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
	<init-param>
         <param-name>time</param-name>
         <param-value>600</param-value>
      </init-param>
      <init-param>
         <param-name>scope</param-name>
         <param-value>session</param-value>
      </init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<!-對所有jsp頁面內容進行緩存-->
<url-pattern>*.jsp</url-pattern>
</filter-mapping>

5 性能測試結果


5.1 測試環境


系統平臺:windows 2000 高級服務器/ P3 800 /512M內存

web服務器:websphere 5.0

數據庫服務器:mysql 4.0.18-nt

性能測試用工具:apache Jmeter

5.2 測試計劃


這次性能測試對比方為使用緩存和不使用緩存兩種,他們的訪問代碼都是一樣的:通過數據源從本地mysql數據庫中獲取person表的所有記錄,然后顯示在頁面上。

測試中將模仿10個用戶,每個用戶發起5次請求,然后統計所有訪問花費的時間。

5.3 測試結果


使用緩存后的測試結果 不使用緩存時的測試結果

所有請求花費的總時間(毫秒) 20569 22870

性能測試的詳細結果請大家查看下載內容中的《不使用cache時的系統性能測試結果.txt》和《使用cache后系統性能測試結果.txt》

6 總結


在J2EE系統中,我們經常需要處理一些特殊的動態內容,這些內容在一個時間段內的變更非常有限,但是又不得不將他們確定為動態內容進行輸出,而且非常消耗數據庫系統資源或者web服務器的資源,這時我們就可以采用Cache----一種用于提高系統響應速度、改善系統運行性能的技術----來優化我們的系統。尤其是在Web應用中,這種處理可以很顯著的改善系統運行性能。

本文中作者給大家介紹一個實現J2EE框架中Web應用層緩存功能的開放源代碼項目----OSCache。它提供了在J2EE系統中實現緩存需要的豐富的功能。通過應用OSCache,我們不但可以實現通常的Cache功能、自由的設定cache的相關特性比如緩存時間段/緩存內容等,提升系統性能,而且還能有效的改善系統的穩定性。除此之外,OSCache組件還提供了更多的特性比如集群、容錯、靈活的緩存區選擇等。

作者根據自己的使用經驗給大家提供了一些簡單的例子,他們部分演示了如何使用OSCache組件提供的豐富特性,OSCache提供的特性遠不止這些,需要大家在今后的時間里深入的研究,同時也希望大家通過E-mail和作者貢獻研究成果。



jackstudio 2006-09-09 10:06 發表評論
]]>
oscache 使用1http://www.tkk7.com/jackstudio/archive/2006/09/08/68568.htmljackstudiojackstudioFri, 08 Sep 2006 09:57:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/09/08/68568.htmlhttp://www.tkk7.com/jackstudio/comments/68568.htmlhttp://www.tkk7.com/jackstudio/archive/2006/09/08/68568.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/68568.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/68568.htmlOSCache各版本下載頁面:http://www.opensymphony.com/oscache/download.action

○用二分鐘配置:

將下載的oscache-2.1.1-full.zip解壓,你會看到oscache-2.1.1.jar 及一些目錄 docs、etc、lib、src。
現在將 etc目錄下oscache.properties?、oscache.tld 及 oscache-2.1.1.jar 文件復制到你的應用服務器目錄下

使用tomcat,jdk1.4 配置例:
???????? D:\Tomcat 5.0\webapps\ROOT\WEB-INF\lib\oscache-2.1.1.jar
???????? D:\Tomcat 5.0\webapps\ROOT\WEB-INF\classes\oscache.properties
???????? D:\Tomcat 5.0\webapps\ROOT\WEB-INF\classes\oscache.tld

oscache.properties 文件配置參數說明:
cache.memory
值為true 或 false ,默認為在內存中作緩存,
如設置為false,那cache只能緩存到數據庫或硬盤中,那cache還有什么意義:)
cache.capacity
緩存元素個數
cache.persistence.class
持久化緩存類,如此類打開,則必須設置cache.path信息
cache.cluster 相關
為集群設置信息。如
cache.cluster.multicast.ip為廣播IP地址
cache.cluster.properties為集群屬性

再將 D:\Tomcat 5.0\webapps\ROOT\WEB-INF\web.xml 文件中添加如下代碼
<taglib>
<taglib-uri>oscache</taglib-uri>
<taglib-location>/WEB-INF/classes/oscache.tld</taglib-location>
</taglib>

就是這么簡單,OSCache就配置好了。

○再用二分鐘測試一下

編寫jsp文件
======================cache1.jsp 內容如下=================
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="java.util.*" %>
<%@ taglib uri="oscache" prefix="cache" %>
<html>
<body>
沒有緩存的日期: <%= new Date() %><p>
<!--自動刷新-->
<cache:cache time="30">
每30秒刷新緩存一次的日期: <%= new Date() %> <p>
</cache:cache>

<!--手動刷新-->
<cache:cache key="testcache">
手動刷新緩存的日期: <%= new Date() %> <p>
</cache:cache>
<a /></body>
</html>
=========================================================

====================cache2.jsp 執行手動刷新頁面如下===========
<%@ page contentType="text/html;charset=GBK"%>
<%@ taglib uri="oscache" prefix="cache" %>
<html>
<body>緩存已刷新...<p>

<cache:flush key="testcache" scope="application"/>

<a /></body>
</html>
==========================================================???????

其他: 緩存過濾器 CacheFilter
可以讓你所有.jsp頁面自動緩存。

你可以在web.xml中定義緩存過濾器,定義特定資源的緩存。
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
<init-param>
<param-name>time</param-name>
<param-value>60</param-value>
</init-param>
<init-param>
<param-name>scope</param-name>
<param-value>session</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
上面定義將緩存所有.jsp頁面,緩存刷新時間為60秒,緩存作用域為Session

注意,CacheFilter只捕獲Http頭為200的頁面請求,即只對無錯誤請求作緩存,
而不對其他請求(如500,404,400)作緩存處理

此文完。。謝謝觀看。



jackstudio 2006-09-08 17:57 發表評論
]]>
OSCache使用經驗總結http://www.tkk7.com/jackstudio/archive/2006/09/08/68569.htmljackstudiojackstudioFri, 08 Sep 2006 09:57:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/09/08/68569.htmlhttp://www.tkk7.com/jackstudio/comments/68569.htmlhttp://www.tkk7.com/jackstudio/archive/2006/09/08/68569.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/68569.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/68569.htmlOSCache使用經驗總結
????????????????????????????? OSCache使用經驗總結
OSCache的使用主要有4種:
POJO 緩存
HTTP Response 緩存
JSP Tag Library 緩存
O/R Data Access 緩存

1、POJO 緩存
這種方式的緩存直接調用OSCache的API進行,主要用于處理頁面內容會根據參數動態改變,可以將參數設置為key值來保存數據:
首先,聲明成員變量:
?// OSCache Adminitrator instance
?private static GeneralCacheAdministrator cacheAdmin = null;
其次,進行初始化:
?public RingArtistAction() {
? cacheAdmin = new GeneralCacheAdministrator();
?}
將POJO進行緩存:
? // Cache data key and refresh period
? String key = sex + ":" + place;
? int refreshPeriod = Constants.getIntegerValue(Constants.OSCACHE_REFRESH_PERIOD).intValue();
? try {
????? // Get from the cache
?? artists = (Map) cacheAdmin.getFromCache(key, refreshPeriod);
? } catch (NeedsRefreshException nre) {
????? try {
????????? // Get the value (probably from the database)
??? int count = getArtistCount(sex, place, errors);
??? artists = getArtistData(sex, place, count, errors);
????????? // Store in the cache
??? cacheAdmin.putInCache(key, artists);
????? } catch (Exception ex) {
????????? // We have the current content if we want fail-over.
??? artists = (Map) nre.getCacheContent();
????????? // It is essential that cancelUpdate is called if the
????????? // cached content is not rebuilt
??? cacheAdmin.cancelUpdate(key);
??? ex.printStackTrace();
????? }
? }
?
2、HTTP Response 緩存
這種方式的緩存用來處理整個頁面的內容固定,不會根據參數動態改變:
首先在web.xml中配置CacheFilter:
?<filter>
? <filter-name>CacheFilter</filter-name>
? <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
? <init-param>
?? <param-name>time</param-name>
?? <param-value>86400</param-value>
? </init-param>
? <init-param>
?? <param-name>scope</param-name>
?? <param-value>application</param-value>
? </init-param>
?</filter>
將所有需要緩存的頁面加入filter-mapping:
?<filter-mapping>
? <filter-name>Set Character Encoding</filter-name>
? <url-pattern>/*</url-pattern>
?</filter-mapping>
注意,只有返回狀態為200(HttpServletResponse.SC_OK)的內容才會被緩存

3、JSP Tag 緩存
JSP Tag緩存主要用于緩存JSP頁面的局部內容:
? <cache:cache key="especialcategory" cron="* 5 * * *">
? <jsp:include page="/ringcategory.do" flush="true" >
??? <jsp:param name="ringType" value="1"/>
? </jsp:include>
? </cache:cache>

4、O/R Data Access 緩存
請閱讀參考資料的內容獲取詳情。

參考資料:
Taking the load off: OSCache helps databases cope:http://www.theserverside.com/articles/article.tss?l=OSCacheHelpsDatabases

?



jackstudio 2006-09-08 17:57 發表評論
]]>
正規表達式java.util.regex包 http://www.tkk7.com/jackstudio/archive/2006/06/17/53484.htmljackstudiojackstudioSat, 17 Jun 2006 08:21:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/06/17/53484.htmlhttp://www.tkk7.com/jackstudio/comments/53484.htmlhttp://www.tkk7.com/jackstudio/archive/2006/06/17/53484.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/53484.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/53484.html ? [轉]正規表達式java.util.regex包
? 來源:http://www.52blog.net/user1/53795/archives/2006/653150.shtml

現在JDK1.4里有了自己的正則表達式API包,JAVA程序員可以免去找第三方提供的正則表達式庫的周折了,我們現在就馬上來了解一下這個SUN提供的遲來恩物- -對我來說確實如此。

1.簡介:
java.util.regex是一個用正則表達式所訂制的模式來對字符串進行匹配工作的類庫包。
它包括兩個類:Pattern和Matcher Pattern 一個Pattern是一個正則表達式經編譯后的表現模式。
Matcher 一個Matcher對象是一個狀態機器,它依據Pattern對象做為匹配模式對字符串展開匹配檢查。 首先一個Pattern實例訂制了一個所用語法與PERL的類似的正則表達式經編譯后的模式,然后一個Matcher實例在這個給定的Pattern實例的模式控制下進行字符串的匹配工作。
以下我們就分別來看看這兩個類:

2.Pattern類:
Pattern的方法如下: static Pattern compile(String regex)
將給定的正則表達式編譯并賦予給Pattern類
static Pattern compile(String regex, int flags)
同上,但增加flag參數的指定,可選的flag參數包括:CASE INSENSITIVE,MULTILINE,DOTALL,UNICODE CASE, CANON EQ
int flags()
返回當前Pattern的匹配flag參數.
Matcher matcher(CharSequence input)
生成一個給定命名的Matcher對象
static boolean matches(String regex, CharSequence input)
編譯給定的正則表達式并且對輸入的字串以該正則表達式為模開展匹配,該方法適合于該正則表達式只會使用一次的情況,也就是只進行一次匹配工作,因為這種情況下并不需要生成一個Matcher實例。
String pattern()
返回該Patter對象所編譯的正則表達式。
String[] split(CharSequence input)
將目標字符串按照Pattern里所包含的正則表達式為模進行分割。
String[] split(CharSequence input, int limit)
作用同上,增加參數limit目的在于要指定分割的段數,如將limi設為2,那么目標字符串將根據正則表達式分為割為兩段。

一個正則表達式,也就是一串有特定意義的字符,必須首先要編譯成為一個Pattern類的實例,這個Pattern對象將會使用matcher()方法來生成一個Matcher實例,接著便可以使用該 Matcher實例以編譯的正則表達式為基礎對目標字符串進行匹配工作,多個Matcher是可以共用一個Pattern對象的。

現在我們先來看一個簡單的例子,再通過分析它來了解怎樣生成一個Pattern對象并且編譯一個正則表達式,最后根據這個正則表達式將目標字符串進行分割:
import java.util.regex.*;
public class Replacement{
public static void main(String[] args) throws Exception {
// 生成一個Pattern,同時編譯一個正則表達式
Pattern p = Pattern.compile("[/]+");
//用Pattern的split()方法把字符串按"/"分割
String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/ 凱文已經看過《這個殺手不太冷》幾次了,因為它是一部"
+"好電影。/名詞:凱文。");
for (int i=0; i<result.length; i++)
System.out.println(result[i]);
}
}

輸出結果為:

Kevin has seen《LEON》seveal times,because it is a good film.
凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。
名詞:凱文。

很明顯,該程序將字符串按"/"進行了分段,我們以下再使用 split(CharSequence input, int limit)方法來指定分段的段數,程序改動為:
tring[] result = p.split("Kevin has seen《LEON》seveal times,because it is a good film./ 凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。/名詞:凱文。",2);

這里面的參數"2"表明將目標語句分為兩段。

輸出結果則為:

Kevin has seen《LEON》seveal times,because it is a good film.
凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。/名詞:凱文。

由上面的例子,我們可以比較出java.util.regex包在構造Pattern對象以及編譯指定的正則表達式的實現手法與我們在上一篇中所介紹的Jakarta-ORO 包在完成同樣工作時的差別,Jakarta-ORO 包要先構造一個PatternCompiler類對象接著生成一個Pattern對象,再將正則表達式用該PatternCompiler類的compile()方法來將所需的正則表達式編譯賦予Pattern類:

PatternCompiler orocom=new Perl5Compiler();

Pattern pattern=orocom.compile("REGULAR EXPRESSIONS");

PatternMatcher matcher=new Perl5Matcher();

但是在java.util.regex包里,我們僅需生成一個Pattern類,直接使用它的compile()方法就可以達到同樣的效果:
Pattern p = Pattern.compile("[/]+");

因此似乎java.util.regex的構造法比Jakarta-ORO更為簡潔并容易理解。

3.Matcher類:
Matcher方法如下: Matcher appendReplacement(StringBuffer sb, String replacement)
將當前匹配子串替換為指定字符串,并且將替換后的子串以及其之前到上次匹配子串之后的字符串段添加到一個StringBuffer對象里。
StringBuffer appendTail(StringBuffer sb)
將最后一次匹配工作后剩余的字符串添加到一個StringBuffer對象里。
int end()
返回當前匹配的子串的最后一個字符在原目標字符串中的索引位置 。
int end(int group)
返回與匹配模式里指定的組相匹配的子串最后一個字符的位置。
boolean find()
嘗試在目標字符串里查找下一個匹配子串。
boolean find(int start)
重設Matcher對象,并且嘗試在目標字符串里從指定的位置開始查找下一個匹配的子串。
String group()
返回當前查找而獲得的與組匹配的所有子串內容
String group(int group)
返回當前查找而獲得的與指定的組匹配的子串內容
int groupCount()
返回當前查找所獲得的匹配組的數量。
boolean lookingAt()
檢測目標字符串是否以匹配的子串起始。
boolean matches()
嘗試對整個目標字符展開匹配檢測,也就是只有整個目標字符串完全匹配時才返回真值。
Pattern pattern()
返回該Matcher對象的現有匹配模式,也就是對應的Pattern 對象。
String replaceAll(String replacement)
將目標字符串里與既有模式相匹配的子串全部替換為指定的字符串。
String replaceFirst(String replacement)
將目標字符串里第一個與既有模式相匹配的子串替換為指定的字符串。
Matcher reset()
重設該Matcher對象。
Matcher reset(CharSequence input)
重設該Matcher對象并且指定一個新的目標字符串。
int start()
返回當前查找所獲子串的開始字符在原目標字符串中的位置。
int start(int group)
返回當前查找所獲得的和指定組匹配的子串的第一個字符在原目標字符串中的位置。


(光看方法的解釋是不是很不好理解?不要急,待會結合例子就比較容易明白了)

一個Matcher實例是被用來對目標字符串進行基于既有模式(也就是一個給定的Pattern所編譯的正則表達式)進行匹配查找的,所有往Matcher的輸入都是通過CharSequence接口提供的,這樣做的目的在于可以支持對從多元化的數據源所提供的數據進行匹配工作。

我們分別來看看各方法的使用:

★matches()/lookingAt ()/find():
一個Matcher對象是由一個Pattern對象調用其matcher()方法而生成的,一旦該Matcher對象生成,它就可以進行三種不同的匹配查找操作:

matches()方法嘗試對整個目標字符展開匹配檢測,也就是只有整個目標字符串完全匹配時才返回真值。
lookingAt ()方法將檢測目標字符串是否以匹配的子串起始。
find()方法嘗試在目標字符串里查找下一個匹配子串。

以上三個方法都將返回一個布爾值來表明成功與否。

★replaceAll ()/appendReplacement()/appendTail():
Matcher類同時提供了四個將匹配子串替換成指定字符串的方法:

replaceAll()
replaceFirst()
appendReplacement()
appendTail()

replaceAll()與replaceFirst()的用法都比較簡單,請看上面方法的解釋。我們主要重點了解一下appendReplacement()和appendTail()方法。

appendReplacement(StringBuffer sb, String replacement) 將當前匹配子串替換為指定字符串,并且將替換后的子串以及其之前到上次匹配子串之后的字符串段添加到一個StringBuffer對象里,而appendTail(StringBuffer sb) 方法則將最后一次匹配工作后剩余的字符串添加到一個StringBuffer對象里。

例如,有字符串fatcatfatcatfat,假設既有正則表達式模式為"cat",第一次匹配后調用appendReplacement(sb,"dog"),那么這時StringBuffer sb的內容為fatdog,也就是fatcat中的cat被替換為dog并且與匹配子串前的內容加到sb里,而第二次匹配后調用appendReplacement(sb,"dog"),那么sb的內容就變為fatdogfatdog,如果最后再調用一次appendTail(sb),那么sb最終的內容將是fatdogfatdogfat。

還是有點模糊?那么我們來看個簡單的程序:
//該例將把句子里的"Kelvin"改為"Kevin"
import java.util.regex.*;
public class MatcherTest{
public static void main(String[] args)
throws Exception {
//生成Pattern對象并且編譯一個簡單的正則表達式"Kelvin"
Pattern p = Pattern.compile("Kevin");
//用Pattern類的matcher()方法生成一個Matcher對象
Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working in Kelvin Chen's KelvinSoftShop company");
StringBuffer sb = new StringBuffer();
int i=0;
//使用find()方法查找第一個匹配的對象
boolean result = m.find();
//使用循環將句子里所有的kelvin找出并替換再將內容加到sb里
while(result) {
i++;
m.appendReplacement(sb, "Kevin");
System.out.println("第"+i+"次匹配后sb的內容是:"+sb);
//繼續查找下一個匹配對象
result = m.find();
}
//最后調用appendTail()方法將最后一次匹配后的剩余字符串加到sb里;
m.appendTail(sb);
System.out.println("調用m.appendTail(sb)后sb的最終內容是:"+ sb.toString());
}
}

最終輸出結果為:
第1次匹配后sb的內容是:Kevin
第2次匹配后sb的內容是:Kevin Li and Kevin
第3次匹配后sb的內容是:Kevin Li and Kevin Chan are both working in Kevin
第4次匹配后sb的內容是:Kevin Li and Kevin Chan are both working in Kevin Chen's Kevin
調用m.appendTail(sb)后sb的最終內容是:Kevin Li and Kevin Chan are both working in Kevin Chen's KevinSoftShop company.

看了上面這個例程是否對appendReplacement(),appendTail()兩個方法的使用更清楚呢,如果還是不太肯定最好自己動手寫幾行代碼測試一下。

★group()/group(int group)/groupCount():
該系列方法與我們在上篇介紹的Jakarta-ORO中的MatchResult .group()方法類似(有關Jakarta-ORO請參考上篇的內容),都是要返回與組匹配的子串內容,下面代碼將很好解釋其用法:
import java.util.regex.*;

public class GroupTest{
public static void main(String[] args)
throws Exception {
Pattern p = Pattern.compile("(ca)(t)");
Matcher m = p.matcher("one cat,two cats in the yard");
StringBuffer sb = new StringBuffer();
boolean result = m.find();
System.out.println("該次查找獲得匹配組的數量為:"+m.groupCount());
for(int i=1;i<=m.groupCount();i++){
System.out.println("第"+i+"組的子串內容為: "+m.group(i));
}
}
}

輸出為:
該次查找獲得匹配組的數量為:2
第1組的子串內容為:ca
第2組的子串內容為:t

Matcher對象的其他方法因比較好理解且由于篇幅有限,請讀者自己編程驗證。

4.一個檢驗Email地址的小程序:
最后我們來看一個檢驗Email地址的例程,該程序是用來檢驗一個輸入的EMAIL地址里所包含的字符是否合法,雖然這不是一個完整的EMAIL地址檢驗程序,它不能檢驗所有可能出現的情況,但在必要時您可以在其基礎上增加所需功能。
import java.util.regex.*;
public class Email {
public static void main(String[] args) throws Exception {
String input = args[0];
//檢測輸入的EMAIL地址是否以 非法符號"."或"@"作為起始字符
Pattern p = Pattern.compile("^\\.|^\\@");
Matcher m = p.matcher(input);
if (m.find()){
System.err.println("EMAIL地址不能以'.'或'@'作為起始字符");
}
//檢測是否以"www."為起始
p = Pattern.compile("^www\\.");
m = p.matcher(input);
if (m.find()) {
System.out.println("EMAIL地址不能以'www.'起始");
}
//檢測是否包含非法字符
p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");
m = p.matcher(input);
StringBuffer sb = new StringBuffer();
boolean result = m.find();
boolean deletedIllegalChars = false;
while(result) {
//如果找到了非法字符那么就設下標記
deletedIllegalChars = true;
//如果里面包含非法字符如冒號雙引號等,那么就把他們消去,加到SB里面
m.appendReplacement(sb, "");
result = m.find();
}
m.appendTail(sb);
input = sb.toString();
if (deletedIllegalChars) {
System.out.println("輸入的EMAIL地址里包含有冒號、逗號等非法字符,請修改");
System.out.println("您現在的輸入為: "+args[0]);
System.out.println("修改后合法的地址應類似: "+input);
}
}
}

例如,我們在命令行輸入:java Email www.kevin@163.net

那么輸出結果將會是:EMAIL地址不能以'www.'起始

如果輸入的EMAIL為@kevin@163.net

則輸出為:EMAIL地址不能以'.'或'@'作為起始字符

當輸入為:cgjmail#$%@163.net

那么輸出就是:

輸入的EMAIL地址里包含有冒號、逗號等非法字符,請修改
您現在的輸入為: cgjmail#$%@163.net
修改后合法的地址應類似: cgjmail@163.net

5.總結:
本文介紹了jdk1.4.0-beta3里正則表達式庫--java.util.regex中的類以及其方法,如果結合與上一篇中所介紹的Jakarta-ORO API作比較,讀者會更容易掌握該API的使用,當然該庫的性能將在未來的日子里不斷擴展,希望獲得最新信息的讀者最好到及時到SUN的網站去了解。

6.結束語:
本來計劃再多寫一篇介紹一下需付費的正則表達式庫中較具代表性的作品,但覺得既然有了免費且優秀的正則表達式庫可以使用,何必還要去找需付費的呢,相信很多讀者也是這么想的:,所以有興趣了解更多其他的第三方正則表達式庫的朋友可以自己到網上查找或者到我在參考資料里提供的網址去看看。



jackstudio 2006-06-17 16:21 發表評論
]]>
在myeclipse中配置weblogic[轉]http://www.tkk7.com/jackstudio/archive/2006/06/02/49893.htmljackstudiojackstudioFri, 02 Jun 2006 03:31:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/06/02/49893.htmlhttp://www.tkk7.com/jackstudio/comments/49893.htmlhttp://www.tkk7.com/jackstudio/archive/2006/06/02/49893.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/49893.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/49893.html安裝WebLogic8.1
安裝WebLogic比較容易,在這里就不再累述了,大家可以參閱相關文檔。現在著重講一下WebLogic的配置,因為后面在配置MyEclipse時將用到這里的有關信息。
(1)運行開始\程序\BEA WebLogic PlatFORM 8.1\Configuration Wizard。
(2)選擇Create a new WebLogic configuration,下一步。
(3)選擇Basic WebLogic Server Domain,下一步。
(4)選擇Custom,下一步。
(5)在Name處輸入admin,Listen Address處選擇localhost,以下兩個Port均采用默認值,下一步。
(6)選擇Skip跳過Multiple Servers,Clusters,and Machines Options,下一步。
(7)選擇Skip跳過JDBC連接池的配置(注:JDBC連接池的配置可以在啟動WebLogic后到控制臺上進行,大家可以參閱相關文檔),下一步。
(選擇Skip跳過JMS的配置(同樣留到控制臺上做),下一步。
(9)繼續跳過,下一步。
(10)選擇Yes,下一步。
(11)在User頁點擊Add,隨意添加一個用戶user,密碼12345678,下一步。
(12)將用戶user分配到Administrators組(還可以同時分配到其它組,方法是選中待加入的組,然后勾中user前的復選框即可),下一步。
(13)直接點擊下一步跳過。
(14)設置用戶user的權限,選中Admin,勾中user前的復選框(要指定其它權限依次類推),下一步。
(15)采用默認設置,直接點擊下一步跳過。
(16)同樣采用默認設置,直接點擊下一步跳過。
(17)配置JDK,采用WebLogic的默認值,直接點擊下一步跳過。
(1最后在Configuration Name處輸入dev,然后點擊Create生成配置,完畢點擊Done關閉Configuration Wizard對話框。
5.配置MyEclipse的WebLogic服務器
MyEclipse默認的應用服務器為JBoss3,這里我們使用WebLogic8.1。啟動Eclipse,選擇“窗口\首選項”菜單,打開首選項對話框。展開MyEclipse下的Application Servers結點,點擊JBoss 3,選中右面的Disable單選按鈕,停用JBoss 3。然后點擊WebLogic 8,選中右邊的Enable單選按鈕,啟用WebLogic服務器。同時下面的配置如下:
(1)BEA home directory:D:\BEA。假定WebLogic安裝在D:\BEA文件夾中。
(2)WebLogic installation directory:D:\BEA\weblogic81。
(3)Admin username:user。
(4)Admin password:12345678。
(5)Execution domain root:D:\BEA\user_projects\dev。
(6)Execution domain name:dev。
(7)Execution server name:admin。
(8)Hostname:PortNumber:localhost:7001。
(9)Security policy file:D:\BEA\weblogic81\server\lib\weblogic.policy。
(10)JAAS login configuration file:省略。
接著展開WebLogic 8結點,點擊JDK,在右邊的WLS JDK name處選擇WebLogic 8的默認JDK。這里組合框中缺省為j2re1.4.2_03,即之前單獨安裝的jre。單擊Add按鈕,彈出WebLogic > Add JVM對話框,在JRE名稱處隨便輸入一個名字,如jre1.4.1_02。然后在JRE主目錄處選擇WebLogic安裝文件夾中的JDK文件夾,如D:\BEA\jdk141_02,程序會自動填充Javadoc URL文本框和JRE系統庫列表框。單擊確定按鈕關閉對話框。這時候就可以在WLS JDK name組合框中選擇jre1.4.1_02了。之后還要在下面的Optional Java VM arguments,如-ms64m -mx64m -Djava.library.path="D:/BEA/weblogic81/server/bin" -Dweblogic.management.discover=false -Dweblogic.ProductionModeEnabled=false
最后點擊Paths,在右邊的Prepend to classpath列表框中,通過Add JAR/ZIP按鈕,加入D:\BEA\weblogic81\server\lib\weblogic.jar、D:\BEA\weblogic81\server\lib\webservices.jar。如果用到數據庫,還需把數據庫的驅動類庫加進來,這里我們用WebLogic自帶的SQL Server數據庫驅動庫D:\BEA\weblogic81\server\lib\mssqlserver4v65.jar。
至此,MyEclipse中WebLogic8的配置工作就算完成了。下面可以看看在Eclipse中能否啟動WebLogic了?自從安裝了MyEclipse之后,Eclipse工具欄中就會有一個Run/Stop Servers下拉按鈕。點擊該按鈕的下拉部分,選擇“WebLogic 8\Start”菜單,即開始啟動WebLogic了。通過查看下面的控制臺消息,就可以知道啟動是否成功,或有什么異常發生。停止WebLogic可選擇“WebLogic\Stop”菜單。



jackstudio 2006-06-02 11:31 發表評論
]]>
struts1.1基于dbcp下的mysql數據庫的數據源配置http://www.tkk7.com/jackstudio/archive/2006/05/31/49324.htmljackstudiojackstudioWed, 31 May 2006 12:09:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/05/31/49324.htmlhttp://www.tkk7.com/jackstudio/comments/49324.htmlhttp://www.tkk7.com/jackstudio/archive/2006/05/31/49324.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/49324.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/49324.html分別是
1.commons-dbcp-1.2.1.jar
2.commons-pool-1.2.jar
3.struts-legacy.jar
4.mysqldriver.jar


點這里全部下載

????<data-sources>

????????
<data-source?type="org.apache.commons.dbcp.BasicDataSource">
????????????
<set-property?property="driverClassName"?value="org.gjt.mm.mysql.Driver"?/>
????????????
<set-property?property="url"?value="jdbc:mysql://localhost/userinfo?useUnicode=true&amp;characterEncoding=GB2312"?/>
????????????
<set-property?property="username"?value="root"?/>
????????????
<set-property?property="password"?value=""?/>
????????????
<set-property?property="maxActive"?value="10"?/>
????????????
<set-property?property="maxWait"?value="5000"?/>
????????????
<set-property?property="defaultAutoCommit"?value="false"?/>
????????????
<set-property?property="defaultReadOnly"?value="false"?/>
????????????
<set-property?property="validationQuery"?value="SELECT?COUNT(*)?FROM?myuserinfo"?/>
????????
</data-source>

????
</data-sources>


jackstudio 2006-05-31 20:09 發表評論
]]>
Java/JSP中文亂碼問題解決心得http://www.tkk7.com/jackstudio/archive/2006/05/31/49296.htmljackstudiojackstudioWed, 31 May 2006 08:54:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/05/31/49296.htmlhttp://www.tkk7.com/jackstudio/comments/49296.htmlhttp://www.tkk7.com/jackstudio/archive/2006/05/31/49296.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/49296.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/49296.html

Java/JSP中文亂碼問題解決心得

作者信息:liqian??liqianbnu@126.com?? http://202.112.88.39/liqian/
文章原始出處:http://202.112.88.39/liqian/000271.html

自從接觸Java和JSP以來,就不斷與Java的中文亂碼問題打交道,現在終于得到了徹底的解決,現將我們的解決心得與大家共享。

一、Java中文問題的由來

Java的內核和class文件是基于unicode的,這使Java程序具有良好的跨平臺性,但也帶來了一些中文亂碼問題的麻煩。原因主要有兩方面,Java和JSP文件本身編譯時產生的亂碼問題和Java程序于其他媒介交互產生的亂碼問題。

首先Java(包括JSP)源文件中很可能包含有中文,而Java和JSP源文件的保存方式是基于字節流的,如果Java和JSP編譯成class文件過程中,使用的編碼方式與源文件的編碼不一致,就會出現亂碼。基于這種亂碼,建議在Java文件中盡量不要寫中文(注釋部分不參與編譯,寫中文沒關系),如果必須寫的話,盡量手動帶參數-ecoding GBK或-ecoding gb2312編譯;對于JSP,在文件頭加上<%@ page contentType="text/html;charset=GBK"%>或<%@ page contentType="text/html;charset=gb2312"%>基本上就能解決這類亂碼問題。

本文要重點討論的是第二類亂碼,即Java程序與其他存儲媒介交互時產生的亂碼。很多存儲媒介,如數據庫,文件,流等的存儲方式都是基于字節流的,Java程序與這些媒介交互時就會發生字符(char)與字節(byte)之間的轉換,具體情況如下:

從頁面form提交數據到java程序 byte->char
從java程序到頁面顯示 char—>byte

從數據庫到java程序 byte—>char
從java程序到數據庫 char—>byte

從文件到java程序 byte->char
從java程序到文件 char->byte

從流到java程序 byte->char
從java程序到流 char->byte

如果在以上轉換過程中使用的編碼方式與字節原有的編碼不一致,很可能就會出現亂碼。

二、解決方法

前面已經提到了Java程序與其他媒介交互時字符和字節的轉換過程,如果這些轉換過程中容易產生亂碼。解決這些亂碼問題的關鍵在于確保轉換時使用的編碼方式與字節原有的編碼方式保持一致,下面分別論述(Java或JSP自身產生的亂碼請參看第一部分)。

1、JSP與頁面參數之間的亂碼
JSP獲取頁面參數時一般采用系統默認的編碼方式,如果頁面參數的編碼類型和系統默認的編碼類型不一致,很可能就會出現亂碼。解決這類亂碼問題的基本方法是在頁面獲取參數之前,強制指定request獲取參數的編碼方式:request.setCharacterEncoding("GBK")或request.setCharacterEncoding("gb2312")。
如果在JSP將變量輸出到頁面時出現了亂碼,可以通過設置response.setContentType("text/html;charset=GBK")或response.setContentType("text/html;charset=gb2312")解決。
如果不想在每個文件里都寫這樣兩句話,更簡潔的辦法是使用Servlet規范中的過慮器指定編碼,過濾器的在web.xml中的典型配置和主要代碼如下:
web.xml:

<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>net.vschool.web.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

CharacterEncodingFilter.java:

public class CharacterEncodingFilter implements Filter
{

protected String encoding = null;

public void init(FilterConfig filterConfig) throws ServletException
{
this.encoding = filterConfig.getInitParameter("encoding");
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
chain.doFilter(request, response);
}

}


2、Java與數據庫之間的亂碼
大部分數據庫都支持以unicode編碼方式,所以解決Java與數據庫之間的亂碼問題比較明智的方式是直接使用unicode編碼與數據庫交互。很多數據庫驅動自動支持unicode,如Microsoft的SQLServer驅動。其他大部分數據庫驅動,可以在驅動的url參數中指定,如如mm的mysql驅動:jdbc:mysql://localhost/WEBCLDB?useUnicode=true&characterEncoding=GBK。

3、Java與文件/流之間的亂碼
Java讀寫文件最常用的類是FileInputStream/FileOutputStream和FileReader/FileWriter。其中FileInputStream和FileOutputStream是基于字節流的,常用于讀寫二進制文件。讀寫字符文件建議使用基于字符的FileReader和FileWriter,省去了字節與字符之間的轉換。但這兩個類的構造函數默認使用系統的編碼方式,如果文件內容與系統編碼方式不一致,可能會出現亂碼。在這種情況下,建議使用FileReader和FileWriter的父類:InputStreamReader/OutputStreamWriter,它們也是基于字符的,但在構造函數中可以指定編碼類型:InputStreamReader(InputStream in, Charset cs) 和OutputStreamWriter(OutputStream out, Charset cs)。

4、其他
上面提到的方法應該能解決大部分亂碼問題,如果在其他地方還出現亂碼,可能需要手動修改代碼。解決Java亂碼問題的關鍵在于在字節與字符的轉換過程中,你必須知道原來字節或轉換后的字節的編碼方式,轉換時采用的編碼必須與這個編碼方式保持一致。我們以前使用Resin服務器,使用smartUpload組件上傳文件,上傳文件同時傳遞的中文參數獲取沒有亂碼問題。當在Linux中把Resin設置成服務后,上傳文件同時的中文參數獲取出現了亂碼。這個問題困擾了我們很久,后來我們分析smartUpload組件的源文件,因為文件上傳采用的是字節流的方式,里面包含的參數名稱和值也是字節流的方式傳遞的。smartUpload組件讀取字節流后再將參數名稱和值從字節流中解析出來,問題就出現在smartUpload將字節流轉換成字符串時采用了系統默認的編碼,而將Resin設置成服務后,系統默認的編碼可能發生了改變,因此出現了亂碼。后來,我們更改了smartUpload的源文件,增加了一個屬性charset和setCharset(String)方法,將upload()方法中提取參數語句:
String value = new String(m_binArray, m_startData, (m_endData - m_startData) + 1 );
改成了
String value = new String(m_binArray, m_startData, (m_endData - m_startData) + 1, charset );
終于解決了這個亂碼問題。

三、后記
接觸Java和JSP已經有一年多了,這一年來最大的收獲是越來越喜歡上了Java,開始把問題當作樂事去研究,沒有了以前的恐懼心理,我相信我會繼續堅持下去。這一年來,從網上學習了很多同行的寶貴經驗,在此表示感謝。這是我第一篇自己總結的Java學習心得,由于水平有限,本文中偏頗和錯誤之處,歡迎指正。如果對你有些價值,在保留作者信息和文章原始出處的前提下可以隨處轉載。
撰寫該文之前已參考了很多關于Java中文問題的文章,其中影響比較大的有owen1944在“Java研究組織”中發表的《這是我們公司總結的一些關于中文亂碼問題的一些解決方案和經驗和大家分享!》等。本文談到的解決方法已應用到“基于網絡的協作學習系統-WebCL”等項目中,并通過資源綁定的方式實現了該平臺中文文兩個版本的即時切換。Google根據瀏覽器自動選擇語言,一個頁面同時顯示多種語言的國際化應用和車東的《Java中文處理學習筆記——Hello Unicode》一文引起了我極大的興趣,日后想將繼續探討Java的國際化問題,歡迎大家一起討論。



jackstudio 2006-05-31 16:54 發表評論
]]>
關于Myeclipse的困擾。。。。http://www.tkk7.com/jackstudio/archive/2006/05/31/49283.htmljackstudiojackstudioWed, 31 May 2006 08:18:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/05/31/49283.htmlhttp://www.tkk7.com/jackstudio/comments/49283.htmlhttp://www.tkk7.com/jackstudio/archive/2006/05/31/49283.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/49283.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/49283.html
Myeclipse4.1.1內置的struts1.1中<html:errors />不能正常工作。

我的resourses如下:
#?Resources?for?parameter?'com.jackstudio.struts.ApplicationResources'
#?Project?P
/MyEclipseTest
userNameIsNull
=<li>userName?is?require</li>
whyNot
=<li>whyNot</li>
okgood
=the?userName?is?right
errors.footer
=</td></tr></table></fieldset>
errors.header
=<fieldset><table><tr><td><img?src="http://localhost:8080/MyEclipseTest/ico_tj_24.gif"></td><td>

首先我用Myeclipse4.1.1內置的struts1.1。代碼如下;

????????<%ActionErrors?errors?=?new?ActionErrors();
????????????errors.add(ActionMessages.GLOBAL_MESSAGE,?
new?ActionMessage("userNameIsNull"));
????????????request.setAttribute(Globals.ERROR_KEY,?errors);

????????
%>
????????
<html:errors?/>

這樣的情況運行的結果是:

org.apache.jasper.JasperException:?org.apache.struts.action.ActionMessage
????org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:
372)
????org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:
292)
????org.apache.jasper.servlet.JspServlet.service(JspServlet.java:
236)
????javax.servlet.http.HttpServlet.service(HttpServlet.java:
802)

當我用孫mm提供的(隨書提供)struts,相同的代碼卻可以運行。
經過仔細查找,發現問題是出在了struts.jar這個文件里面。兩者的大小根本都一樣了(呵呵),于是用孫mm提供的struts.jar覆蓋了MyEclipse里面的struts.jar,呵呵,問題解決了。
MyEclipse每建立一個struts項目都是從
{MyEclipse}\eclipse\plugins\com.genuitec.eclipse.cross.easystruts.eclipse_4.1.1\data\1.1\lib下讀取struts.jar包的。所以替換了它就可以一勞永逸了。


jackstudio 2006-05-31 16:18 發表評論
]]>
myeclipse4.1.1注冊碼http://www.tkk7.com/jackstudio/archive/2006/05/25/48072.htmljackstudiojackstudioThu, 25 May 2006 09:07:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/05/25/48072.htmlhttp://www.tkk7.com/jackstudio/comments/48072.htmlhttp://www.tkk7.com/jackstudio/archive/2006/05/25/48072.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/48072.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/48072.htmlMyEclipse 開發組近日宣布,MyEclipse 4.1 正式發布。

報道中指出,該新版本中出現的新特性正如之前所期待的,主要包括:

AJAX/Web 2.0 支持
JavaScript Editor 提升
新的JavaScript Debbugger 和Web 2.0 平臺和瀏覽器
UML序列圖標支持
Spring/Hibernate 集成
新的Hibernate 映射編輯工具
提高了拖放性能
Visual Web Designer Zoom
JSP 本地察看
提高的服務器管理性能
New Image Editor for Eclipse 3.1

下載地址: http://www.myeclipseide.com/

不好用你找我

下載地址:http://www.myeclipseide.com/ContentExpress-display-ceid-10.html
4.1及4.1.1注冊碼:
junsan
wLR8ZC-956-55-5467865000966531
或者
inpsiresky.com
vLR8ZC-956-55-54678656095533727

jackstudio 2006-05-25 17:07 發表評論
]]>
Java中的常用方法 http://www.tkk7.com/jackstudio/archive/2006/05/21/47321.htmljackstudiojackstudioSun, 21 May 2006 11:20:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/05/21/47321.htmlhttp://www.tkk7.com/jackstudio/comments/47321.htmlhttp://www.tkk7.com/jackstudio/archive/2006/05/21/47321.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/47321.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/47321.html 第一章 字符串

1、 獲取字符串的長度:length()
2、判斷字符串的前綴或后綴與已知字符串是否相同
前綴 startsWith(String s)、后綴 endsWith(String s)
3、比較兩個字符串:equals(String s)
4、把字符串轉化為相應的數值
int型 Integer.parseInt(字符串)、long型 Long.parseLong(字符串)
float型 Folat.valueOf(字符串).floatValue()
double型 Double.valueOf(字符串).doubleValue()
5、
將數值轉化為字符串:valueOf(數值)
6、 字符串檢索
indexOf(Srting s) 從頭開始檢索
indexOf(String s ,int startpoint) 從startpoint處開始檢索
如果沒有檢索到,將返回-1
7、 得到字符串的子字符串
substring(int startpoint) 從startpoint處開始獲取
substring(int start,int end) 從start到end中間的字符
8、 替換字符串中的字符,去掉字符串前后空格
replace(char old,char new) 用new替換old
9、 分析字符串
StringTokenizer(String s) 構造一個分析器,使用默認分隔字符(空格,換行,回車,Tab,進紙符)
StringTokenizer(String s,String delim) delim是自己定義的分隔符
nextToken() 逐個獲取字符串中的語言符號
boolean hasMoreTokens() 只要字符串還有語言符號將返回true,否則返回false
countTokens() 得到一共有多少個語言符號

第二章 文本框和文本區

1、文本框
TextField() 構造文本框,一個字符長、TextField(int x) 構造文本框,x個字符長
TextField(String s) 構造文本框,顯示s、setText(String s) 設置文本為s
getText() 獲取文本、setEchoChar(char c) 設置顯示字符為c
setEditable(boolean) 設置文本框是否可以被修改、addActionListener() 添加監視器
removeActionListener() 移去監視器
2、文本區
TextArea() 構造文本區;TextArea(String s) 構造文本區,顯示s
TextArea(String s,int x,int y) 構造文本區,x行,y列,顯示s
TextArea(int x,int y) 構造文本區,x行,y列
TextArea(String s,int x,ing y,int scrollbar)
scrollbar的值是:
TextArea.SCROLLBARS_BOTHTextArea.SCROLLBARS_VERTICAL_ONLY
TextArea.SCROLLBARS_HORIZONTAL_ONLY;TextArea.SCROLLBARS_NONE
setText(String s) 設置文本為s;getText() 獲取文本
addTextListener() 添加監視器;removeTextListener() 移去監視器
insert(String s,int x) 在x處插入文本s
replaceRange(String s,int x,int y) 用s替換從x到y處的文本
append(String s) 在文本的最后追加文本s
Int getCaretPosition(int n) 獲取文本區中光標的位置

第三章 按鈕

1、按鈕
Button() 構造按鈕;Button(String s) 構造按鈕,標簽是s
setLabel(String s) 設置按鈕標簽是s;getLabel() 獲取按鈕標簽
addActionListener() 添加監視器;removeActionListener() 移去監視器

第四章 標簽

1、標簽
Label() 構造標簽;Label(String s) 構造標簽,顯示s
Label(String s,int x)x是對齊方式,取值:Label.LEFT;Label.RIGHT;Label.CENTER
setText(String s) 設置文本s;getText() 獲取文本
setBackground(Color c) 設置標簽背景顏色;setForeground(Color c) 設置字體顏色

第五章 選擇框

1、選擇框
Checkbox() 構造選擇框;Checkbox(String s) 構造選擇框,給定標題s
Checkbox(String s,boolean b) b設定初始狀態
Checkbox(String s,boolean b,CheckboxGroup g) g設定了所屬的組(有了組就成為單選框)
addItemListener() 添加監視器;removeItemListener() 移去監視器
getState() 返回選擇框的是否選中狀態;setState(boolean b) 設置選擇框的狀態
getLabel() 獲取選擇框的標題;setLabel(String s) 設置選擇框的標題為s

第六章 選擇控件和滾動列表

1、選擇控件
Choice() 構造選擇控件;add(String s) 向選擇控件增加一個選項
addItemListener() 添加監視器;removeItemListener() 移去監視器
getSelectedIndex() 返回當前選項的索引;getSelectedItem() 返回當前選項的字符串代表
insert(String s,int n) 在n處插入選項s
remove(int n);removeAll()
2、滾動列表
List() 構造滾動列表;List(int n) 參數n是可見行數
List(int n,boolean b) 參數b是設置是否可以多項選擇
add(String s) 向列表的結尾增加一個選項;add(String s,int n) 在n處增加一個選項
AddActionListener() 滾動列表添加監視器
addItemListener() 滾動列表上的選項添加監視器
remove(int n) 刪除n初的選項;remnoveAll() 刪除全部選項
getSelectedIndex() 返回當前選項的索引;getSelectedItem() 返回當前選項的字符串代表
3、組件類的一些常用方法
void setBackground(Color c) 設置組件背景顏色
void setForeground(Color c) 設置組件前景顏色
void setFonts(Font f) 設置組件字體
void setBounds(int x,int y,int w,int h) 設置坐標,x,y表示在容器中坐標,w,h表示寬和高
void setLocation(int x,int y) 移動到x,y 處;void setSize(int w,int h) 設置寬和高
void setVisible(boolean b) 設置組建是否可見
int getBounds().wigth 獲取寬;int getBounds().height 獲取高
int getBounds().x 獲取x 坐標;int getBounds().y 獲取y 坐標
Toolkit getToolkit() 獲取工具包對
void setEnabled(boolean b) 設置是否可以使用(默認可以)

第七章 窗口和菜單

1、窗口
Frame() 構造窗口;Frame(String s) 窗口標題是s
setBounds(int x,int y,int w,int h) 窗口位置x,y,寬w,高y
setSize(int w,int h) 設置窗口位置(單位是像素)
setBackground(Color c) 設置背景顏色;setVisible(boolean b) 設置窗口是否可見
pack() 窗口出現時緊湊;setTitle(String s) 設置標題為s
getTitle() 獲取標題;setResizable(boolean b) 設置窗口大小是否可以調整
2、菜單條
Menubar() 構造菜單條;setMenubar() 窗口添加菜單條
3、菜單
Menu() 構造菜單;Menu(String s) 構造菜單,標題s
add(MenuItem item) 菜單增加菜單選項item;add(String s) 向菜單增加選項s
getItem(int n) 獲取n處的選項;getItemCount() 獲取選項數目
insert(MenuItem item,int n) 在n處插入菜單選項item
insert(String s,int n) 在n處插入菜單選項
remove(int n) 刪除菜單的n處的菜單選項;removeAll() 刪除全部
4、菜單項
MenuItem() 構造菜單項;MenuItem(String s) 構造標題是s的菜單項
setEnabled(boolean b) 設置是否可以被選擇;getLabel() 得到菜單選項名
addActionListener() 添加監視器
5、有關菜單的技巧
addSeparator() 增加菜單分割線;CheckboxMenuItem() 復選框菜單項
setShortcut(MenuShortcut k) 設置快捷鍵(k取值KeyEvent.VK_A----KeyEvent.VK_Z)

第八章 建立對話框

1、Dialog類
Dialog(Frame f,String s) 構造對話框,初始不可見,s是標題,f是對話框所依賴的窗口
Dialog(Frame f,String s,boolean b) b設置初始是否可見
getTitle() 獲取對話框標題;setTitle(String s) 設置對話框標題
setModal(boolean b) 設置對話框模式;setSize(int w,int h) 設置對話框大小
setVisible(boolean b) 顯示或隱藏對話框
2、FileDialog類
Filedialog(Frame f,String s,int mode) mode的值是fileDialog.LOAD或者fileDialog.SAVE
public String getDirectory() 獲取當前文件對話框中顯示的文件所屬目錄
public String getFile() 獲取當前文件對話框中文件的字符串表示,不存在返回null

第九章 Java中的鼠標和鍵盤事件

1、使用MouseListener借口處理鼠標事件
鼠標事件有5種:按下鼠標鍵,釋放鼠標鍵,點擊鼠標鍵,鼠標進入和鼠標退出
鼠標事件類型是MouseEvent,主要方法有:
getX(),getY() 獲取鼠標位置;getModifiers() 獲取鼠標左鍵或者右鍵
getClickCount() 獲取鼠標被點擊的次數;getSource() 獲取鼠標發生的事件源
事件源獲得監視器的方法addMouseListener(),移去監視器的方法removeMouseListener()
處理事件源發生的時間的事件的接口是MouseListener 接口中有如下的方法
mousePressed(MouseEvent) 負責處理鼠標按下事件
mouseReleased(MouseEvent) 負責處理鼠標釋放事件
mouseEntered(MouseEvent) 負責處理鼠標進入容器事件
mouseExited(MouseEvent) 負責處理鼠標離開事件
mouseClicked(MouseEvent) 負責處理點擊事件
2、使用MouseMotionListener接口處理鼠標事件
事件源發生的鼠標事件有2種:拖動鼠標和鼠標移動;鼠標事件的類型是MouseEvent
事件源獲得監視器的方法是addMouseMotionListener()
處理事件源發生的事件的接口是MouseMotionListener 接口中有如下的方法
mouseDragged() 負責處理鼠標拖動事件;mouseMoved() 負責處理鼠標移動事件
3、控制鼠標的指針形狀
setCursor(Cursor.getPreddfinedCursor(Cursor.鼠標形狀定義)) 鼠標形狀定義見(書 P 210)
4、鍵盤事件
鍵盤事件源使用addKeyListener 方法獲得監視器
鍵盤事件的接口是KeyListener 接口中有3個方法
public void keyPressed(KeyEvent e) 按下鍵盤按鍵
public void keyReleased(KeyEvent e) 釋放鍵盤按鍵
public void keyTypde(KeyEvent e) 按下又釋放鍵盤按鍵

第十章 Java多線程機制

1、Java的線程類與Runnable接口
Thread類
public Thread() 創建線程對象;? public Thread(Runnable target)
target稱為被創建線程的目標對象,負責實現Runnable
線程優先級
Thread類有三個有關線程優先級的靜態常量:MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY
新建線程將繼承創建它的副線程的優先級。
用戶可以調用Thread類的setPriority(int a)來修改a的取值:
Thread.MIN_PRIORITY,Thread.MAX_PRIORITY,Thread.NORM_PRIORITY
主要方法
啟動線程 start();定義線程操作 run()
使線程休眠 sleep():sleep(int millsecond) 以毫秒為單位的休眠時間
sleep(int millsecond,int nanosecond) 以納秒為單位的休眠時間
currentThread() 判斷誰在占用CPU的線程

第十一章 輸入輸出流

1、FileInputStream類
FileInputStream(String name) 使用給定的文件名name創建一個FileInputStream對象
FileInputStream(File file) 使用File對象創建FileInpuStream對象
File類有兩個常用方法:
File(String s) s確定文件名字;File(String directory,String s) directory是文件目錄
處理I/O異常
當出現I/O錯誤的時候,Java生成一個IOException(I/O異常)對象來表示這個錯誤的信號。
程序必須使用一個catch檢測這個異常

從輸入流中讀取字節
int read() 返回0~255之間一個整數,如果到輸入流末尾,則返回-1
int read(byte b[]) 讀取字節數組
int read(byte b[],int off,int len):
off指定把數據存放在b中什么地方,len指定讀取的最大字節數
關閉流
close()
2、FileOutputStream類
FileOutputStream(String name) 使用指定的文件名name創建FileOutputStream對象
FileOutputStream(File file) 使用file對象創建FileOutputStream對象
FileOutputStream(FileDescriptor fdobj) 使用FileDescriptor對象創建FileOutputStream對象
3、FileReader類和FileWriter類
FileReader(String filename);FileWriter(String filename)
處理時需要FileNotFoundException異常
4、RandomAccessFile類
RandomAccessFile不同于FileInputStream和FileOutputStream,不是他們的子類
當我們想對一個文件進行讀寫操作的時候,創建一個指向該文件的RandomAccessFile流就行了
RandomAccessFile類有兩個構造方法:
RandomAccessFile(String name, String mode) name是文件名,mode取r(只讀)或rw(讀寫)
RandomAccessFile(File file,String mode) file給出創建流的源
seek(long a) 移動RandomAccessFile流指向文件的指針,a確定指針距文件開頭的位置
getFilePointer() 獲取當前文件的指針位置;close() 關閉文件
getFD() 獲取文件的FileDescriptor;length() 獲取文件長度
read() 讀取一個字節數據;readBoolean() 讀取一個布爾值;readByte() 讀取一個字節
readChar();readFloat();readFully(byte b[]);readInt();readLine();readLong()
readUnsignedShort();readUTF() 讀取一個UTF字符串
setLength(long newLength) 設置文件長度;skipByte(int n) 在文件中跳過給定數量的字節
write(byte b[]) 寫b.length個字節到文件;writeBoolean(bolean b)
writeByte(int v);writeChar(char c);writeChars(String s);writeDouble(double d)
writeFloat(float v);writeInt(int i);writeLong(long l);writeShort(int i)
writeUTF(String s)
5、管道流
PipedInputStream類;PipedInputStream() 創建一個管道輸入流
PipedInputStream(PipedOutputStream a) 連接到輸出流a的輸入流
read() 從輸入流中讀取一個字節
read(byte b[],int off,int len) off是在b中的開始位置,len是字節長度
PipedOutputStream類;PipedOutputStream() 創建一個輸出流
PipedOutputStream(PipedInputStream a) 連接到輸入流a的輸出流
write(int b);write(byte b[],int off,int len)
counnect() 連接輸入輸出流;close() 關閉流;在使用的時候要捕獲IOException異常。
6、數據流
DataInputStream類(數據輸入流)
DataInputStream(InputStream in) 將數據輸入流指向一個由in指定的輸入流
DataOutputStream類(數據輸出流)
DataOutputStream(OutputStream out) 將數據輸出流指向一個由out指定的輸出流
主要方法:
close();read() 讀取一個字節數據;readBoolean() 讀取一個布爾值
readByte() 讀取一個字節;readChar();readFloat();readFully(byte b[])
readInt();readLine();readLong();readUnsignedShort()
readUTF() 讀取一個UTF字符串;skipByte(int n) 在文件中跳過給定數量的字節
write(byte b[]) 寫b.length個字節到文件;writeBoolean(bolean b)
writeByte(int v);writeChar(char c);writeChars(String s);
writeDouble(double d);writeFloat(float v);writeInt(int i)
writeLong(long l);writeShort(int i);writeUTF(String s)
7、對象流
ObjectInputStream類和ObjectOutputStream類分別是DataInputStream類和DataOutputStream類的子類
8、回壓輸入流
PushbackInputStream類;PushbackInputStream(InputStream in)
PushbackReader類;PushbackReader(Reader in)
unread(char c) 回壓一個字符;unread(char c[]) 回壓數組c中全部字符
unread(char c[],offset,int n) 回壓c中從offset開始的n個字符

第十二章 java網絡的基本知識

1、使用URL(統一資源定位)
例如:
try
{
url=new URL("}
catch(MalformedURLException e)
{
System.out.println("Bad
);
}
在Applet 中鏈接向另外的Web頁面,使用代碼:
getAppletContext().showDocument(url);
2、套接字
客戶建立到服務器的套接字(Socket)
Socket(String host,int port) host是服務器的IP地址,port是端口號
建立了套接字后可以使用getInputStream()獲得輸入流
還可以使用getOutputStream()獲得一個輸出流
服務器建立接受客戶套接字的服務器套接字(ServerSocket)
ServerSocket(int port) port是端口號
建立了套接字連接后可以使用accept()接收客戶的套接字
可以使用getOutputStream()獲得一個輸出流
還可以使用getInputStream()獲得一個輸入流
3、InetAddress類
getByName(String s) 獲取Internet上主機的地址
getHostName() 獲取InetAddress對象所包含的域名
getHostAddress() 獲取InetAddress對象所包含的IP地址
getLocalHost() 獲取本地地址
4、UDP數據報
發送數據包,即使用DatagramPacket類將數據打包,有兩種構造方法
DatagramPacket(byte data[],int length,InetAddress address,int port)
?含有data數組的數據
?該數據包將發送到地質是address,端口是port的主機上
DatagramPacket(byte data[],int offset,int length,InetAddress address,int port)
?含有data數組的從offset開始,length長度的數據
?該數據包將發送到地質是address,端口是port的主機上
接收數據包,即使用DatagramSocket(int port)創建一個對象,port必須和待接收的數據包的端口相同
例如:
如果發送方的數據包端口是5566
DatagramSocket mail=new DatagramSocket(5566);
然后對象mail可以使用方法receive(Datagrampacket pack)接收數據包
在使用參數pack 接收數據包前,必須創建pack
byte data[]=new byte[100];
int length=90;
DatagramPacket pack=new DatagramPataet(data,length);
mail.receive(pack);
該數據包pack將接收長度是length的數據放入data,注意數據長度不要超過8192KB
pack還可以調用方法getPort()獲取所接受數據包是從什么端口發出的
調用方法InetAddress getAddress()可以獲知數據包來自哪個主機

第十三章 Java與圖像

1、java支持的圖像類型:GIF,JPEG,BMP
2、Image類
首先申請一個Image對象
Image img =getImage(URL url,String name) url是圖像地址,name是圖片名稱
通常使用:
Image img =getImage(getCodBase(),String name) getCodBase()獲取當前小應用程序的URL,也就是在同一目錄下
圖像被加載后,就可以在paint()中繪制了
drawImage(Image img,int x,int y,ImageObserver observer)
img是上面獲取的圖像, x,y是指定圖像左上角的位置,observer是加載圖像時的圖像觀察器
Applet類已經實現了ImageObserver接口,所以可以直接使用this作為最后一個參數
drawImage(Image img,int x,int y,int width,int height,ImageObserver observer)
width和height是要繪制的圖像的寬和高
可以使用img.getHeight(this)和img.getWidth(this)來獲取被加載的圖像的寬和高
3、設置Java窗口圖標
Frame對象可以使用setIconImage(Image img)方法設置左上角圖標,默認圖標是咖啡杯

第十四章 Java數據庫連接(JDBC)

1、JDBC-ODBC橋接器
建立JDBC-ODBC橋接器
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver";
}
catch(ClassNotFoundException e){}
連接到數據庫
try
{
Connection con=DriverManager.getConnection("jdbc:jdbc:數據源名稱","數據源的login name",
"數據源的password"
}
catch(SQLException e){}
向數據庫發送SQL語句
try
{
Statement sql=con.createStatement();
}
catch(SQLException e){}
處理查詢結果
ResultSet rs=sql.executeQuery("SQL語句";

第十五章 Java與多媒體

1、在小程序中播放聲音
java可以播放au,aiff,wav,midi,rfm格式的音頻
可以調用Applet的一個靜態方法:
newAudioClip(URL url,String name) url是地址,name是音頻名稱
也可以用Applet類的實例方法:
getAudioClip(URL url,String name)
根據url地址和聲音文件name,獲得一個用于播放的音頻對象,這對象可以使用下面的方法來處理聲音:
play() 播放聲音文件name;loop() 循環播放name;stop() 停止播放name
2、Java媒體框架(JMF)
創建播放器
try
{
URL url=new URL(getDocumenBase(),視頻文件名稱);
player player=Manager.createPlayer(url);
}
catch(IOException e){}
向播放器注冊控制監視器
player.addControllerListener(監視器);
創建監視器必須使用接口ControllerListener ,該接口中的方法是
public void controllerUpdate(ControllerEvent e)
讓播放器對媒體進行預提取:player.prefetch()
啟動播放器:player.start();
停止播放器:player.stop();
停止播放器后必須釋放內存中的資源:player.deallocate();

第十六章 Java Swing基礎

1、Jcomponent類
Jcomponent類 是所有輕量組件的父類,主要的子類有:
JButton 創建按鈕對象,而且可以創建在圖標的按鈕;
JTree 創建樹對象
JComboBox 創建組合框對象,和Choice相似;JCheckBox 創建復選框對象
JFileChooser 創建文件選擇器;JInternalFrame 創建內部窗體
JLabel 創建標簽;JMenu 創建菜單對象;JMenuBar 創建菜單條對象
JMenuItem 創建菜單項對象;JPanel 創建面板對象;JPasswordField 創建口令文本對象
JPopupMenu 創建彈出式菜單;JProgressBar 創建進程條;JRadioButton 創建單選按鈕
JScrollBar 創建滾動條;JScrollPane 創建滾動窗格;JSlider 創建滾動條
JSplitPane 創建拆分窗格;JTable 創建表格;JTextArea 創建文本區
JTexPane 創建文本窗格;JToolBar 創建工具條;JToolTip 創建工具提示對象
2、JFrame類
JFrame類及其子類創建的對象是窗體
(1)JFrame類及其子類創建的窗體是swing窗體
(2)不可以把組件直接加到swing窗體中,應該把組件加到內容面板中
(3)不能為swing窗體設置布局,而應當為內容面板設置布局
(4)swing窗體通過調用getContentPane()方法得到它的內容面板
3、JApplet類
(1)不可以把組件直接添加到小程序容器中,也應該添加到內容面板中
(2)不能為小程序設置布局
(3)小程序容器通過調用getContenPane()方法得到內容面板
4、JDialog類
(1)不可以把組件直接添加到對話框容器中,也應該添加到內容面板中
(2)不能為對話框設置布局
(3)對話框容器通過調用getContenPane()方法得到內容面板
5、JPanel面板:JPanel();JPanel(布局對象)
6、滾動窗口JScrollPane:JScrollPane();JScrollPane(component c)
7、拆分窗口JSplitPane
JSplitPane(int a,Component b,Component c)
a的取值是HORIZONTAL_SPLIT或者VERTICAL_SPLIT決定水平拆分還是垂直拆分
JSplitPane(int a,boolean b ,Component b,Component c) b的取值決定拆分線移動的時候組件是否連續變化
8、內部窗體JInternalFrame
JInternalFrame(String title,boolean resizable,booleam closable,boolean max,boolean min)
參數的意義分別是窗口名稱,是否能調整大小,是否有關閉按鈕,最大化按鈕,最小化按鈕
(1)不能把組件直接加到窗體中,而是加到內容面板中
(2)必須先把內部窗體加到一個容器中(JDesktopPane),該容器是專門為內部窗體服務的
9、按鈕(JButton)
JButton() 創建按鈕;JButton(String s) s是按鈕的名字
JButton(Icon icon) icon是按鈕上的圖標;JButton(String s,Icon icon)
getText() 獲取按鈕名字;getIcon() 獲取按鈕圖標
setIcon(Icon icon) 設置按鈕圖標
setHorizontalTextposition(int a) a確定按鈕上圖標的位置,取值:
AbstractButton_CENTR,AbstractButton_LEFT,AbstractButton_RIGHT
setVerticalTextposition(int a) a確定按鈕上名字相對圖標的位置,取值:
AbstractButton.TOP,AbstractButton.BOTTOM,AbstractButton.CENTR
setMnemonic(char c) 設置按鈕的鍵盤操作方式是字符c(Alt+c)
setEnabled(boolean b) b決定按鈕是否可以被單擊



jackstudio 2006-05-21 19:20 發表評論
]]>
Log4J使用方法http://www.tkk7.com/jackstudio/archive/2006/04/22/42447.htmljackstudiojackstudioSat, 22 Apr 2006 01:38:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/04/22/42447.htmlhttp://www.tkk7.com/jackstudio/comments/42447.htmlhttp://www.tkk7.com/jackstudio/archive/2006/04/22/42447.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/42447.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/42447.html看了別人寫了那么多的教程,自己也受益不少,現在也把自己學Log4J的體會寫下來.

1.在WEB-INF\classes文件下放入一個java屬性文件,名字為commons-logging.properties,這是一個通用日志文件的配置文件,當然你也可以用xml文件來弄.其內容如下:

#--------------------------------------------------------
#使用Log4J實現
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog

## 使用SimpleLog實現
#org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

后面的值是你想要的實現日志接口的類.apache的commons-logging.jar本身帶了兩個實現,SimpleLog
是其中的一個,如果 你的要使用Log4J,還必須把Log4J大相關jar放到相應的lib下.


2.如果使用SimpleLog,那么在WEB-INF\classes下要有一個simplelog.properties文件,內容:
//---------------------------------------------
org.apache.commons.logging.simplelog.defaultlog = info

主要是定義SimpleLog日志輸出級別.


3.使用Log4J進行日志輸出不僅可以定義輸出的級別,還可以定義輸出的地方和輸出的格式.而simplelog只有System.err.???????? Log4J主要是定義三個Logger,appender 和layout,appender 是輸出的地方,layout就是布局,也就是輸出的格式.
//-----------------------------------------------

## LOGGERS ##
#定義一個logger
log4j.rootLogger=INFO,console,file

## APPENDERS ##
#定義一個appender,后面的紅色字體就是他的名字,可以任意定義.其值是相關的輸出的類.可取值如
#ConsoleAppender
#RollingFileAppender
#DailyRollingFileAppender
..............................................

# log4j.appender.console=org.apache.log4j.ConsoleAppender

log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=log.txt

#如果使用FileAppender那么后面還跟很有多屬性如MaxFileSize,MaxBackupIndex等.

## LAYOUTS ##

# 定義格式
#格式主要有好幾中常用的就是SimpleLayout,HTMLLayout,PatternLayout,使用PatternLayout時后面還要有一個定義格式的ConversionPattern.
log4j.appender.console.layout=org.apache.log4j.SimpleLayout

# PatternLayout
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%t %p - %m%n

#以下是使用的方法:
1.在action,servlet中

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

???????? Log log=LogFactory.getLog("helloapplog");
???????? log.trace("This is a trace message");
???????? log.debug("This is a debug message");
???????? log.info("This is an info message");
???????? log.warn("This is a warn message");
???????? log.error("This is an error message");
???????? log.fatal("This is a fatal message");

2.在jsp中.

?<%@ page import="org.apache.commons.logging.Log" %>
<%@ page import="org.apache.commons.logging.LogFactory" %>
<% Log logger = LogFactory.getLog( this.getClass(? ) ); %>
? <% logger.warn( "This is a warn message from a jsp" ); %>
? <% logger.error( "This is an error message from a jsp" ); %>



jackstudio 2006-04-22 09:38 發表評論
]]>
小弟整理的關于lucene筆記...........http://www.tkk7.com/jackstudio/archive/2006/03/31/38471.htmljackstudiojackstudioFri, 31 Mar 2006 06:01:00 GMThttp://www.tkk7.com/jackstudio/archive/2006/03/31/38471.htmlhttp://www.tkk7.com/jackstudio/comments/38471.htmlhttp://www.tkk7.com/jackstudio/archive/2006/03/31/38471.html#Feedback0http://www.tkk7.com/jackstudio/comments/commentRss/38471.htmlhttp://www.tkk7.com/jackstudio/services/trackbacks/38471.html 記得是看了某位大蝦的blog整理的,可是現在也忘記了這位好人,在次表示感謝這為無名英雄.


lucene學習筆記:

(一)Query
?1.TermQuey//查詢特定的某個Field
?//過程:
?Term t = new Term("subject", "ant");
?//Term構造函數的參數:param1是Field名,param2是用戶查詢的關鍵字
?Query query = new TermQuery(t);
?Hits hits = searcher.Search(query);
?2.QueryParse//簡化查詢語句
?//過程:
?Query query = QueryParser.Parse("+JUNIT +ANT -MOCK","contents",new SimpleAnalyzer());
?Hits hits = searcher.Search(query);
?//注意:TermQuery和QueryParse只要在QueryParse的Parse方法中只有一個word,就會自動轉換成TermQuery.
?3.RangeQuery//范圍查詢,用于查詢范圍,通常用于時間
?//過程:
?RangeQuery query = new RangeQuery(begin, end, true);
?Hits hits = searcher.Search(query);
?//RangeQuery的第三個參數用于表示是否包含該起止日期.Lucene用[] 和{}分別表示包含和不包含.RangeQuery到QueryParse的轉化
?//Query query = QueryParser.Parse("pubmonth:[200004 TO 200206]", "subject", new SimpleAnalyzer());
?//IndexSearcher searcher = new IndexSearcher(directory);
?//Hits hits = searcher.Search(query);
?4.PrefixQuery//搜索是否包含某個特定前綴
?PrefixQuery query = new PrefixQuery(new Term("category", "/Computers"));
?Hits hits = searcher.Search(query);
?5.BooleanQuery//用于測試滿足多個條件
?TermQuery searchingBooks =new TermQuery(new Term("subject", "junit"));
?RangeQuery currentBooks =new RangeQuery(new Term("pubmonth", "200301"),new Term("pubmonth", "200312"),true);
?BooleanQuery currentSearchingBooks = new BooleanQuery();
?currentSearchingBooks.Add(searchingBooks, true, false);
?currentSearchingBooks.Add(currentBooks, true, false);
?IndexSearcher searcher = new IndexSearcher(directory);
?Hits hits = searcher.Search(currentSearchingBooks);
?//什么時候是與什么時候又是或? 關鍵在于BooleanQuery對象的Add方法的參數.
?//參數一是待添加的查詢條件.
?//參數二Required表示這個條件必須滿足嗎? True表示必須滿足, False表示可以不滿足該條件.
?//參數三Prohibited表示這個條件必須拒絕嗎? True表示這么滿足這個條件的結果要排除, False表示可以滿足該條件.
?//BooleanQuery和QueryParse
?[Test]
???????? public void TestQueryParser()
???????? {
????????????? Query query = QueryParser.Parse("pubmonth:[200301 TO 200312] AND junit", "subject", new SimpleAnalyzer());
????????????? IndexSearcher searcher = new IndexSearcher(directory);
????????????? Hits hits = searcher.Search(query);
????????????? Assert.AreEqual(1, hits.Length());
????????????? query = QueryParser.Parse("/Computers/JUnit OR /Computers/Ant", "category", new WhitespaceAnalyzer());
????????????? hits = searcher.Search(query);
????????????? Assert.AreEqual(2, hits.Length());
???????? }

??//注意AND和OR的大小 如果想要A與非B 就用 A AND –B 表示, +A –B也可以.

??//默認的情況下QueryParser會把空格認為是或關系,就象google一樣.但是你可以通過QueryParser對象修改這一屬性.

[Test]
???????? public void TestQueryParserDefaultAND()
???????? {
????????????? QueryParser qp = new QueryParser("subject", new SimpleAnalyzer());
????????????? qp.SetOperator(QueryParser.DEFAULT_OPERATOR_AND );
????????????? Query query = qp.Parse("pubmonth:[200301 TO 200312] junit");
????????????? IndexSearcher searcher = new IndexSearcher(directory);
????????????? Hits hits = searcher.Search(query);
????????????? Assert.AreEqual(1, hits.Length());

???????? }

?6.PhraseQuery//短語查詢
?7.WildcardQuery//通配符搜索
?8.FuzzyQuery//模糊查詢

(二)Analyzer

?WhitespaceAnalyzer:僅僅是去除空格,對字符沒有lowcase化,不支持中文
?SimpleAnalyzer:功能強于WhitespaceAnalyzer,將除去letter之外的符號全部過濾掉,并且將所有的字符lowcase化,
?不支持中文
?StopAnalyzer:StopAnalyzer的功能超越了SimpleAnalyzer,在SimpleAnalyzer的基礎上
??? 增加了去除StopWords的功能,不支持中文
?StandardAnalyzer:英文的處理能力同于StopAnalyzer.支持中文采用的方法為單字切分.
?ChineseAnalyzer:來自于Lucene的sand box.性能類似于StandardAnalyzer,缺點是不支持中英文混和分詞.
?CJKAnalyzer:chedong寫的CJKAnalyzer的功能在英文處理上的功能和StandardAnalyzer相同
??? 但是在漢語的分詞上,不能過濾掉標點符號,即使用二元切分
?最強大的分析程序——StandardAnalyzer類。
?StandardAnalyzer類會將文本的所有內容變成小寫的,并去掉一些常用的停頓詞(stop word)。
?停頓詞是像“a”、“the”和“in”這樣的詞,它們都是內容里非常常見的詞,但是對搜索卻一點用處都沒有。
?分析程序也會分析搜索查詢,這就意味著查詢會找到匹配的部分。例如,
?這段文本“The dog is a golden retriever(這條狗是一只金毛獵犬)”,
?就會被處理為“dog golden retriever”作為索引。當用戶搜索“a Golden Dog”的時候,
?分析程序會處理這個查詢,并將其轉變為“golden dog”,這就符合我們的內容了。


(三)性能問題
?1.切詞,索引,存屬
?域存儲字段規則
?方法 切詞 索引 存儲 用途
?Field.Text(String name, String value) 切分詞索引并存儲,比如:標題,內容字段
?Field.Text(String name, Reader value)? 切分詞索引不存儲,比如:META信息,
?不用于返回顯示,但需要進行檢索內容
?Field.Keyword(String name, String value)? 不切分索引并存儲,比如:日期字段
?Field.UnIndexed(String name, String value)? 不索引,只存儲,比如:文件路徑
?Field.UnStored(String name, String value)? 只全文索引,不存儲
-----------------------------------------------------------------------------------------------
?Keywork
?該類型的數據將不被分析,而會被索引并保存保存在索引中.
?UnIndexed
?該類型的數據不會被分析也不會被索引,但是會保存在索引.
?UnStored
?和UnIndexed剛好相反,被分析被索引,但是不被保存.
?Text
?和UnStrored類似.如果值的類型為string還會被保存.如果值的類型Reader就不會被保存和UnStored一樣.
?
?2.優化索引生成文件
??1.索引的權重SetBoost
???if (GetSenderDomain().EndsWith(COMPANY_DOMAIN))
???//如果是公司郵件,提高權重,默認權重是1.0
?????????? doc.SetBoost(1.5);??????????????????????
???else
???//如果是私人郵件,降低權重.
?????????? doc.SetBoost(0.1);
??不僅如此你還可以對Field也設置權重.比如你對郵件的主題更感興趣.就可以提高它的權重.?
??Field senderNameField = Field.Text("senderName", senderName);
??Field subjectField = Field.Text("subject", subject);
??subjectField.SetBoost(1.2);

??2.利用IndexWriter 屬性對建立索引進行高級管理
???在建立索引的時候對性能影響最大的地方就是在將索引寫入文件的時候所以在具體應用的時候就需要對此加以控制
???IndexWriter屬性??
???描述?? 默認值???備注
???MergeFactory 10????控制segment合并的頻率和大小
???MaxMergeDocs Int32.MaxValue 限制每個segment中包含的文檔數
???MinMergeDocs 10????當內存中的文檔達到多少的時候再寫入segment

???Lucene默認情況是每加入10份文檔就從內存往index文件寫入并生成一個segement,然后每10個segment就合并成一個segment.通過MergeFactory這個變量就可以對此進行控制.
???MaxMergeDocs用于控制一個segment文件中最多包含的Document數.比如限制為100的話,即使當前有10個segment也不會合并,因為合并后的segmnet將包含1000個文檔,超過了限制.
???MinMergeDocs用于確定一個當內存中文檔達到多少的時候才寫入文件,該項對segment的數量和大小不會有什么影響,它僅僅影響內存的使用,進一步影響寫索引的效率.

??3.利用RAMDirectory充分發揮內存的優勢
???在實際應用中RAMDirectory和FSDirectory協作可以更好的利用內存來優化建立索引的時間.
???具體方法如下:
???1.建立一個使用FSDirectory的IndexWriter
???2.建立一個使用RAMDirectory的IndexWriter
???3. 把Document添加到RAMDirectory中
???4. 當達到某種條件將RAMDirectory 中的Document寫入FSDirectory.
???5. 重復第三步

???示意代碼:
????? private FSDirectory fsDir = FSDirectory.GetDirectory("index",true);?

?????? private RAMDirectory ramDir = new RAMDirectory();

?????? private IndexWriter fsWriter = IndexWriter(fsDir,new SimpleAnalyzer(), true);
?????? private IndexWriter ramWriter = new IndexWriter(ramDir,new SimpleAnalyzer(), true);
?????? while (there are documents to index)
????? {
???????? ramWriter.addDocument(doc);
???????? if (condition for flushing memory to disk has been met)
???????? {
?????????? fsWriter.AddIndexes(Directory[]{ramDir}) ;
?????????? ramWriter.Close();????????? //why not support flush?
?????????? ramWriter =new IndexWriter(ramDir,new SimpleAnalyzer(),true);
???????? }
???? }
???這里的條件完全由用戶控制,而不是FSDirectory采用對Document計數的方式控制何時寫入文件.
???相比之下有更大的自由性,更能提升性能.
??4.控制索引內容的長度
???Lucene對一份文本建立索引時默認的索引長度是10,000. 你可以通過IndexWriter 的MaxFieldLength屬性對此加以修改.還是用一個例子說明問題.
??5.Optimize 優化

=------------------------jackstudio-----------------



jackstudio 2006-03-31 14:01 發表評論
]]>
主站蜘蛛池模板: 亚洲精品福利网站| 亚洲欧洲日产国码久在线观看| 亚洲免费在线视频播放| 免费黄网站在线看| 国产亚洲精品自在久久| 99精品视频免费| 亚洲AV综合色区无码另类小说| 色www永久免费网站| 亚洲精品成人网站在线观看| 中文字幕免费在线播放| 亚洲av无码不卡一区二区三区| 日韩电影免费观看| 亚洲成a人片在线观看播放| 一个人在线观看视频免费| 久久精品亚洲日本波多野结衣| 四虎永久免费地址在线网站| 黄色三级三级三级免费看| 久久久久亚洲精品天堂久久久久久 | 色偷偷亚洲女人天堂观看欧| 成年女人色毛片免费看| 在线亚洲精品视频| 亚洲精品成人网站在线观看| 在线看无码的免费网站| 最新国产成人亚洲精品影院| 免费在线观看亚洲| 你好老叔电影观看免费| 亚洲最大视频网站| 免费人成激情视频| 久久久久国产免费| 亚洲日韩AV一区二区三区中文| 亚洲成aⅴ人片久青草影院| a级午夜毛片免费一区二区| 亚洲人成在线中文字幕| 国产人妖ts在线观看免费视频| a级毛片免费完整视频| 亚洲一区在线观看视频| 免费在线黄色网址| 久久国产高潮流白浆免费观看 | 四虎永久在线精品免费影视 | 亚洲Av无码乱码在线观看性色| 国产无遮挡无码视频免费软件|