posts - 40,  comments - 7,  trackbacks - 0
           
          The Grammar of the Java Programming Language
          Identifier:
          ??????? IDENTIFIER

          QualifiedIdentifier:
          ??????? Identifier { . Identifier }

          Literal:
          ??????? IntegerLiteral
          ??????? FloatingPointLiteral
          ??????? CharacterLiteral
          ??????? StringLiteral
          ??????? BooleanLiteral
          ??????? NullLiteral

          Expression:
          ??????? Expression1 [AssignmentOperator Expression1]]

          AssignmentOperator:

          ??????? =
          ??????? +=
          ??????? -=
          ??????? *=
          ??????? /=
          ??????? &=
          ??????? |=
          ??????? ^=
          ??????? %=
          ??????? <<=
          ??????? >>=
          ??????? >>>=

          Type:
          ??????? Identifier [TypeArguments]{?? .?? Identifier [TypeArguments]} {
          []}
          ??????? BasicType

          TypeArguments:
          ??????? < TypeArgument {, TypeArgument} >

          TypeArgument:
          ??????? Type
          ???????
          ? [( extends |super ) Type]

          StatementExpression:
          ??????? Expression

          ConstantExpression:
          ??????? Expression

          Expression1:
          ??????? Expression2 [Expression1Rest]

          Expression1Rest:
          ??????? ? ? Expression? :?? Expression1

          Expression2 :
          ??????? Expression3 [Expression2Rest]

          Expression2Rest:
          ??????? {InfixOp Expression3}
          ??????? Expression3 instanceof Type

          InfixOp:

          ??????? ||
          ??????? &&
          ??????? |
          ??????? ^
          ??????? &
          ??????? ==
          ??????? !=
          ??????? <
          ??????? >
          ??????? <=
          ??????? >=
          ??????? <<
          ??????? >>
          ??????? >>>
          ??????? +
          ??????? -
          ??????? *
          ??????? /
          ??????? %

          Expression3:
          ??????? PrefixOp Expression3
          ???????
          (?? Expression | Type? ) ? Expression3
          ??????? Primary {Selector} {PostfixOp}

          Primary:
          ??????? ParExpression
          ??????? NonWildcardTypeArguments (ExplicitGenericInvocationSuffix
          | this
          Arguments)

          ? this[Arguments]
          ? superSuperSuffix
          ??????? Literal

          ? newCreator
          ??????? Identifier { . Identifier }[ IdentifierSuffix]
          ??????? BasicType {
          []} .class
          ?? void.class

          IdentifierSuffix:
          ??????? [ ( ] {[]} .?? class | Expression ])
          ??????? Arguments
          ??????? .?? (
          class | ExplicitGenericInvocation | this | superArguments | new
          [NonWildcardTypeArguments] InnerCreator )

          ExplicitGenericInvocation:
          ??????? NonWildcardTypeArguments ExplicitGenericInvocationSuffix

          NonWildcardTypeArguments:
          ??????? < TypeList >


          ExplicitGenericInvocationSuffix:
          ???? super SuperSuffix
          ??????? Identifier Arguments


          PrefixOp:

          ??????? ++
          ??????? --
          ??????? !
          ??????? ~
          ??????? +
          ??????? -

          PostfixOp:

          ??????? ++
          ??????? --

          Selector: Selector:
          ??????? . Identifier [Arguments]
          ??????? . ExplicitGenericInvocation
          ??????? .
          this
          ?? .super SuperSuffix
          ??????? . new [NonWildcardTypeArguments] InnerCreator
          ??????? [ Expression ]

          SuperSuffix:
          ??????? Arguments
          ??????? . Identifier [Arguments]

          BasicType:

          ? byte
          ? short
          ? char
          ? int
          ? long
          ? float
          ? double
          ? boolean

          Arguments:
          ??????? ( [Expression { , Expression }] )

          Creator:
          ??????? [NonWildcardTypeArguments] CreatedName ( ArrayCreatorRest? |
          ClassCreatorRest )

          CreatedName:
          ??????? Identifier [NonWildcardTypeArguments] {. Identifier
          [NonWildcardTypeArguments]}

          InnerCreator:
          ??????? Identifier ClassCreatorRest

          ArrayCreatorRest:
          ???????
          [ ( ] {[]} ArrayInitializer | Expression ] {[ Expression ]} {[]} )

          ClassCreatorRest:
          ???????? Arguments [ClassBody]

          ArrayInitializer:
          ??????? { [VariableInitializer {, VariableInitializer} [,]] }

          VariableInitializer:
          ??????? ArrayInitializer
          ??????? Expression

          ParExpression:
          ??????? ( Expression )

          Block:
          ??????? { BlockStatements }

          BlockStatements:
          ??????? { BlockStatement }

          BlockStatement :
          ??????? LocalVariableDeclarationStatement
          ??????? ClassOrInterfaceDeclaration
          ??????? [Identifier :] Statement

          LocalVariableDeclarationStatement:
          ??????? [
          final] Type VariableDeclarators?? ;

          Statement:
          ??????? Block
          ???????
          assert Expression [ : Expression] ;
          ???? if ParExpression Statement [else Statement]
          ???? for ( ForControl ) Statement
          ???? while ParExpression Statement
          ???? do Statement while ParExpression?? ;
          ???? try Block ( Catches | [Catches] finally Block )
          ???? switch ParExpression { SwitchBlockStatementGroups }
          ???? synchronized ParExpression Block
          ???? return [Expression] ;
          ???? throw Expression? ;
          ???? break [Identifier]
          ???? continue [Identifier]
          ???????
          ;
          ??????? StatementExpression
          ;
          ??????? Identifier??
          : ? Statement

          Catches:
          ??????? CatchClause {CatchClause}

          CatchClause:
          ???? catch ( FormalParameter ) Block

          SwitchBlockStatementGroups:
          ??????? { SwitchBlockStatementGroup }

          SwitchBlockStatementGroup:
          ??????? SwitchLabel BlockStatements

          SwitchLabel:
          ???? case ConstantExpression?? :
          ???????
          case EnumConstantName :
          ??????? default?? :

          MoreStatementExpressions:
          ??????? { , StatementExpression }

          ForControl:
          ??????? ForVarControl
          ??????? ForInit;?? [Expression]?? ; [ForUpdate]

          ForVarControl
          ??????? [
          final] [Annotations] Type Identifier ForVarControlRest

          Annotations:
          ??????? Annotation [Annotations]

          Annotation:
          ???????
          @ TypeName [( [Identifier =] ElementValue)]

          ElementValue:
          ??????? ConditionalExpression
          ??????? Annotation
          ??????? ElementValueArrayInitializer

          ConditionalExpression:
          ??????? Expression2 Expression1Rest

          ??? ElementValueArrayInitializer:
          ???????
          { [ElementValues] [,] }

          ??? ElementValues:
          ??????? ElementValue [ElementValues]

          ForVarControlRest:
          ??????? VariableDeclaratorsRest;?? [Expression]?? ;?? [ForUpdate]
          ??????? : Expression

          ForInit:
          ??????? StatementExpression Expressions

          Modifier:
          ? Annotation

          ? public
          ? protected
          ? private
          ? static
          ? abstract
          ? final
          ? native
          ? synchronized
          ? transient
          ? volatile
          ??????? strictfp

          VariableDeclarators:
          ??????? VariableDeclarator { ,?? VariableDeclarator }

          VariableDeclaratorsRest:
          ??????? VariableDeclaratorRest { ,?? VariableDeclarator }

          ConstantDeclaratorsRest:
          ??????? ConstantDeclaratorRest { ,?? ConstantDeclarator }

          VariableDeclarator:
          ??????? Identifier VariableDeclaratorRest

          ConstantDeclarator:
          ??????? Identifier ConstantDeclaratorRest

          VariableDeclaratorRest:
          ??????? {
          []} [? =?? VariableInitializer]

          ConstantDeclaratorRest:
          ??????? {
          []} =?? VariableInitializer

          VariableDeclaratorId:
          ??????? Identifier {
          []}

          CompilationUnit:
          ??????? [[Annotations]
          package QualifiedIdentifier?? ;? ] {ImportDeclaration}
          {TypeDeclaration}

          ImportDeclaration:
          ???? import [ static] Identifier {?? .?? Identifier } [?? .???? *?? ] ;

          TypeDeclaration:
          ??????? ClassOrInterfaceDeclaration
          ??????? ;

          ClassOrInterfaceDeclaration:
          ??????? {Modifier} (ClassDeclaration
          | InterfaceDeclaration)

          ClassDeclaration:
          ??????? NormalClassDeclaration
          ??????? EnumDeclaration

          NormalClassDeclaration:
          ???? class Identifier [TypeParameters] [extends Type] [implements TypeList]
          ClassBody

          TypeParameters:
          ??????? < TypeParameter {, TypeParameter} >

          TypeParameter:
          ??????? Identifier [
          extends Bound]

          Bound:
          ???????? Type {& Type}


          EnumDeclaration:
          ???????
          enum Identifier [implements TypeList] EnumBody

          EnumBody:
          ??????? { [EnumConstants] [,] [EnumBodyDeclarations] }

          EnumConstants:
          ??????? EnumConstant
          ??????? EnumConstants , EnumConstant

          EnumConstant:
          ??????? Annotations Identifier [Arguments] [ClassBody]

          EnumBodyDeclarations:
          ??????? ; {ClassBodyDeclaration}

          InterfaceDeclaration:
          ??????? NormalInterfaceDeclaration
          ??????? AnnotationTypeDeclaration

          NormalInterfaceDeclaration:
          ???? interface Identifier [ TypeParameters] [extends TypeList] InterfaceBody

          TypeList:
          ??????? Type {? ,?? Type}

          AnnotationTypeDeclaration:
          ???????
          @ interface Identifier AnnotationTypeBody

          ??? AnnotationTypeBody:
          ??????? { [AnnotationTypeElementDeclarations] }

          ??? AnnotationTypeElementDeclarations:
          ??????? AnnotationTypeElementDeclaration
          ??????? AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration

          AnnotationTypeElementDeclaration:
          ??????? {Modifier} AnnotationTypeElementRest

          AnnotationTypeElementRest:
          ???????? Type Identifier AnnotationMethodOrConstantRest;
          ??????? ClassDeclaration
          ??????? InterfaceDeclaration
          ??????? EnumDeclaration
          ??????? AnnotationTypeDeclaration

          ??????? AnnotationMethodOrConstantRest:
          ??????? AnnotationMethodRest
          ??????? AnnotationConstantRest

          AnnotationMethodRest:
          ??????? ( ) [DefaultValue]

          AnnotationConstantRest:
          ??????? VariableDeclarators


          ??? DefaultValue:
          ???????
          default ElementValue

          ClassBody:
          ???????
          { {ClassBodyDeclaration} }

          InterfaceBody:
          ???????
          { {InterfaceBodyDeclaration} }

          ClassBodyDeclaration:
          ???????
          ;
          ??????? [
          static] Block
          ??????? {Modifier} MemberDecl

          MemberDecl:
          ??????? GenericMethodOrConstructorDecl
          ??????? MethodOrFieldDecl
          ???????
          void Identifier VoidMethodDeclaratorRest
          ??????? Identifier ConstructorDeclaratorRest
          ??????? InterfaceDeclaration
          ??????? ClassDeclaration

          GenericMethodOrConstructorDecl:
          ??????? TypeParameters GenericMethodOrConstructorRest

          GenericMethodOrConstructorRest:
          ??????? (Type
          | void) Identifier MethodDeclaratorRest
          ??????? Identifier ConstructorDeclaratorRest

          MethodOrFieldDecl:
          ??????? Type Identifier MethodOrFieldRest

          MethodOrFieldRest:
          ??????? VariableDeclaratorRest
          ??????? MethodDeclaratorRest

          InterfaceBodyDeclaration:
          ???????
          ;
          ??????? {Modifier} InterfaceMemberDecl

          InterfaceMemberDecl:
          ??????? InterfaceMethodOrFieldDecl
          ??????? InterfaceGenericMethodDecl
          ???????
          void Identifier VoidInterfaceMethodDeclaratorRest
          ??????? InterfaceDeclaration
          ??????? ClassDeclaration

          InterfaceMethodOrFieldDecl:
          ??????? Type Identifier InterfaceMethodOrFieldRest

          InterfaceMethodOrFieldRest:
          ??????? ConstantDeclaratorsRest ;
          ??????? InterfaceMethodDeclaratorRest

          MethodDeclaratorRest:
          ??????? FormalParameters {
          []} [throwsQualifiedIdentifierList] ( MethodBody |?? ;
          )

          VoidMethodDeclaratorRest:
          ??????? FormalParameters [
          throws QualifiedIdentifierList] ( MethodBody |?? ;? )

          InterfaceMethodDeclaratorRest:
          ??????? FormalParameters {
          []} [throwsQualifiedIdentifierList]? ;

          InterfaceGenericMethodDecl:
          ??????? TypeParameters (Type
          | void) Identifier InterfaceMethodDeclaratorRest

          VoidInterfaceMethodDeclaratorRest:
          ??????? FormalParameters [
          throws QualifiedIdentifierList]?? ;

          ConstructorDeclaratorRest:
          ??????? FormalParameters [
          throws QualifiedIdentifierList] MethodBody

          QualifiedIdentifierList:
          ??????? QualifiedIdentifier {? ,?? QualifiedIdentifier}

          FormalParameters:
          ??????? ( [FormalParameterDecls] )

          FormalParameterDecls:
          ??????? [
          final] [Annotations] Type FormalParameterDeclsRest]

          FormalParameterDeclsRest:
          ??????? VariableDeclaratorId [ , FormalParameterDecls]
          ??????? ... VariableDeclaratorId

          MethodBody:
          ??????? Block

          EnumConstantName:
          ??????? Identifier
          posted @ 2006-08-18 09:00 Lansing 閱讀(375) | 評論 (0)編輯 收藏
          Java Web 應用

          1. Java介紹 
          1.1 什么是Java 
          Java有兩方面的含義:Java語言、Java平臺 

          作為一種語言,Java是一種跨平臺
          開發語言 ,能開發出跨平臺的應用對象和應用程序。例如: Oracle  8i的安裝程序就是用Java開發的。Java語言具有以下特點:簡單、面向對象、分布式、解釋執行、安全、 跨平臺、高性能、多 線程 等特點?!?
          作為一種平臺,Java平臺包括兩部分內容:Java虛擬機和Java API?!?
          1.2 Java之最 
          最好的集成開發工具 
          No1. Visualage For Java (www.ibm.com) 

          No2. 
          JBuilder  3 (www.inprise.com) 

          No3. JDeveloper (www.oracle.com) 

          No4. VisualCafe 

          我推薦使用emacs 

          最好的
          應用服務器  
          No1. WebObjects (www.apple.com) 

          No2. WebSphere Application Server Ent
          ERP rise Edition v3.0 (www.ibm.com) 

          No3. Apache JServ (java.apache.org) 

          No4. WebLogic Server 

          我推薦使用tomcat (jakarta.apache.org), Enhydra (www.enhydra.org) 

          最好的Java類庫 
          No1. The Java Collections (www.sun.com) 

          No2. IBM Host 
          Access  Library API For Java (www.ibm.com) 

          No3. JClass Enterprise (www.klgroup.com) 

          No4. JGL 

          最好的Java中間件 
          No1. 
          Sybase  Enterprise Application Server (www.sybase.com) 

          No2. WebSphere Host On-Demand v4 (www.ibm.com) 

          No3. Progress Sonicmq (www.sonicmq.com) 

          No4. Visiobroker 

          我推薦使用cocoom (
          XML .apache.org),  Struts  (jakarta.apache.org), turbine (java.apache.org) 

          最好的Java組件 
          No1. Bea Jumpstart eBusiness Smart Components (www.bea.com) 

          No2. JClass Enterprise Suite (www.klgroup.com) 

          No3. LingoGUI (www.slangsoft.com) 

          No4. Stdioj 

          最好的
          數據庫 產品 
          No1. Oracle 8i (www.oracle.com) 

          No2. Sybase Adaptive Server Anywhere (www.sybase.com) 

          No3. Cloudscape (www.informix.com) 

          No4. JDataStore 

          我推薦使用PostgreSQL 

          最好的Java虛擬機 
          No1. Java HotSpot Performance Engine (java.sun.com) 

          No2. ChaiVM (www.hewlett-packard.com) 

          No3. JSCP (www.nsicom.com) 

          No4. Jeode Platform 

          最好的消息工具 
          No1. Java Message Queue (www.sun.com) 

          No2. SonicMQ (www.sonicmq.com) 

          No3. FioranoMQ (www.fiorano.com) 

          No4. IBus 

          以上排名來自JDJ Nov 2000統計數據。 

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

          2. ANT 介紹 
          Ant是一個基于java的build工具。大家都知道,現在已經有了許多的build工具,例如make、gnumake、nmake、jam等,而且這些工具都非常優秀。那我為什么還要給大家介紹Ant這個新工具呢? 因為Ant是一個跨平臺的Build工具。之所以Ant能跨平臺,是因為Ant不再需要你編寫shell命令,Ant的配置文件是基于XML的任務樹,能讓你運行各種各樣的任務,任務的運行是由實現了特定任務接口的對象來完成的?!?

          2.1 獲得Ant 
          Binary版:最新的穩定版的
          下載 地址是:http://jakarta.apache.org/builds/ant/release/v1.1/bin。 

          Source版:最新的
          源碼 穩定版下載地址是:http://jakarta.apache.org/builds/ant/release/v1.1/src/。如果你想獲得最新的源碼,地址是:http://jakarta.apache.org/from-cvs/jakarta-ant/ 

          2.2 系統要求 
          需要在CLASSPATH中包含與JAXP兼容的XML parser,才能編譯和使用Ant?!?

          我給大家推薦一個XML parser:xerces,下載地址:http://xml.apache.org/xerces 

          當然,
          JDK 肯定是必需的,并且是1.1或之后版本?!?

          2.3 編譯Ant 
          1. 進入jakarta-ant目錄 

          2. 將JDK加入到你的PATH環境變量中 

          3. 設置JAVA_HOME環境變量,指向你的JDK安裝目錄 

          4. 運行bootstrap.sh角本文件 

          5. 運行以下命令創建Ant的Binary版: 

                     build.sh -Dant.dist.dir=<安裝Ant的目錄> dist


          2.4 安裝Ant 
          1. 設置ANT_HOME環境變量,指向你的Ant目錄 

          2. 設置JAVA_HOME環境變量,指向你的JSK目錄 

          3. 將ANT_HOME/bin加入PATH環境變量中 

          4. 將ant.jar和xerces.jar加入到CLASSPATH環境變量中 

          假設Ant安裝在/usr/local/ant目錄,可通過以下方法進行設置: 

                     export ANT_HOME=/usr/local/ant
                     export JAVA_HOME=/usr/local/jdk-1.2.2
                     export PATH=${ANT_HOME}/bin:${PATH}
                     export CLASSPATH=${ANT_HOME}/lib/ant.jar:/lib/xerces.jar:${CLASSPATH}


          2.5 運行ant 
          運行Ant非常簡單,如果你按照上面描述的方法安裝了ant,只需在命令行鍵入ant就行了?!?

          當你不帶任何參數運行ant時,Ant會在當前目錄找一個名叫build.xml的文件。如果找到了,就將該文件作為build配置文件。如果沒找到,它會自動地查找上級目錄,一直找到根目錄。也可以通過命令行參數 -buildfile  來指定其他配置文件,其中,是你要采用的配置文件名?!?

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

          3. 
          JSP 介紹 
          JSP是JavaServer Pages的簡寫。JSP技術能讓Web開發員和網頁設計員快速地開發容易維護的動態Web主頁?!?

          用JSP開發的Web應用是跨平臺的,即能在
          Linux 下運行,也能在其他 操作系統 上運行?!?

          JSP技術使用Java編程語言編寫類XML的tags和scriptlets,來封裝產生動態網頁的處理邏輯。網頁還能通過tags和scriptlets訪問存在于服務端的資源(例如JavaBesns)的應用邏輯。JSP將網頁邏輯與網頁設計和顯示分離,支持可重用的基于組件的設計,使基于Web的應用程序的開發變得迅速和容易。 

          JSP技術是
          Servlet 技術的擴展。Servlet是平臺無關的,100%純Java的Java服務端組件?!?


          3.1 JSP與jakarta 
          正是因為Jakarta項目組的努力,才使Servlet/JSP據有了前所未有的動力。 

          從Servlet2.2開始,Sun公司已放棄了對Servlet的控制,全權交由Jakarta項目組進行開發和維護。Sun公司不再提供Servlet/JSP的開發包,而是將軟件下載全部鏈接到Jakarta站點,并全力支持Jakarta項目組的開發工作(Jakarta項目組中有部分骨干力量是Sun公司員工)。這是Sun公司的英明決策,也是開源軟件的重大成果?!?

          JSP技術是jakarta所提供的兩大模板技術(JSP和Velocity)之一,這兩個都是非常好的模板技術。jakarta的
          Framework (例如struts、slide)對JSP提供了很好的支持,java.apache的framework(turbine)對Velocity提供了很好的支持?!?


          3.2 運行自己的JSP文件 

          有些網友不知道怎么才能運行自己的JSP文件,我在這里簡單介紹一下,給大家提供一點參考:
          1. 下載并安裝tomcat。下載地址:http://jakarta.apache.org/tomcat
          2. 編寫自己的JSP網頁和Java對象。
          3. 配置自己的Web應用。配置方法:
              在TOMCAT_HOME/conf/server.xml文件中加入一行:

              其中,TOMCAT_HOME是tomcat的主目錄,appName是你的Web應用的名稱。
          4. 將你的jsp文件、html文件、image文件拷貝到TOMCAT_HOME/webapps/appName目錄下。
          5. 編譯你的java文件。
          6. 將編譯好的class文件拷貝到TOMCAT_HOME/webapps/WEB-INF/classes目錄下。也可將class文件打包成jar文件放到TOMCAT_HOME/webapps/WEB-INF/lib目錄下。
          7. ALL IS OK! 你可以在你的瀏覽器上看到你的成果了:
              http://localhost:8080/appName/youjsp.jsp
              其中,appName是你配的Web應用名稱,youjsp.jsp是你編寫的jsp文件名。

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

          4. Tomcat介紹 
          在我寫了一些有關Struts和Framework的貼子后,有人問我什么是tomcat,什么是jakarta。我才發現我應該先寫一些更基本的東西。這篇是介紹tomcat的文章,我還準備寫一篇介紹jakarta的文章?!?


          4.1 什么是Tomcat 
          Tomcat是Java Servlet 2.2和JavaServer Pages 1.1技術的標準實現,是基于Apache許可證下開發的自由軟件?!?


          4.2 Tomcat下載 
          下載地址:http://jakarta.apache.org/downloads/binindex.html 


          4.3 Tomcat和JServ的區別 
          JServ是由Apache開發并使用的Servlet API 2.0兼容的Servlet容器。Tomcat是完全重寫的Servlet API 2.2和JSP 1.1兼容的Servlet/JSP容器。Tomcat使用了JServ的一些代碼,特別是Apache服務適配器?!?


          4.4 什么是servlets,什么是JSPs 
          Servlet為Web開發員提供了一個簡單、一致的機制,來擴展Web
          服務器 的功能,并且和已有的業務系統交互。可以把Servlet看作在服務端運行的 Applet ?!?

          JSP技術是servlet技術的擴展,對HTML和XML的頁面創作提供支持。它網頁設計員能非常容易地將固定或靜態的模板數據與動態內容進行組合?!?

          --------------------------------------------------------------------------------
          我把近一段時間我在論壇中所發的貼子進行了一下整理,形成這篇文檔,以便大家參考,歡迎提出寶貴意見?!∥以趯懽鞅疚脑銜r采用的是sgml格式,通過SGML-Tools轉成你所看到的格式。SGML-Tools是一組文本格式化工具,能將簡單的sgml文檔轉變為格式豐富的各種文件,包括HTML、TeX、DVI、PostScript、plain text、groff等。感謝SGML-Tools的所有開發員所作出的貢獻?!”疚陌鏅鄽w 中文Linux論壇所有。 
          --------------------------------------------------------------------------------
          5. servlet/jsp/xml Frameworks介紹
          5.1 Cocoon - 基于XML的Web內容發布 
          5.2 Xang - 快速開發動態網頁 
          5.3 Slide - 內容管理框架 
          5.4 Struts - 基于M
          VC 設計模式 的JSP 
          5.5 Jetspeed - 基于Web的組件 
          5.6 Turbine - 基于Servlet的Web應用開發 
          5.7 各種Framework比較 

          6. JSP Framework - Struts介紹
          6.1 1、什么是MVC模式?!?
          6.2 2、是否所有JSP應用都該采用MVC模式? 
          6.3 3、Struts中能做XML嗎,與Cocoon相比有何優點? 

          7. Struts的安裝
          7.1 安裝Struts需要的軟件 
          7.2 通過源碼構造Structs 
          7.3 通過Struts的二進制發布包安裝Structs 
          --------------------------------------------------------------------------------

          5. servlet/jsp/xml Frameworks介紹 
          現在,已經有眾多的基于Java的開源Web Framework,讓我們能更加容易構造Web應用。我在這里給大家作一個簡單的介紹?!?


          5.1 Cocoon - 基于XML的Web內容發布 

          Cocoon是采用100%純Java編寫的一個內容發布框架。Cocoon讓你能采用W3C的最新技術(DOM、XML、XSL)來提供Web內容。
          新的Cocoon模式能將文檔內容、樣式、處理邏輯進行完全的分離,允許這三層能獨立地設計、創建和管理,從而減少了管理開銷,加強了工作的重用性,減少了開發時間。
          下載地址:http://xml.apache.org/cocoon



          5.2 Xang - 快速開發動態網頁 
          Xang能整合不同的數據源,讓你能快速地開發數據
          驅動 的、跨平臺的Web應用。Xang體系結構能將數據、邏輯和表示完全劃清。Xang基于開放的工業標準,例如HTTP、XML、XSL、DOM、ECMAScript(JavaScrip)。 

          下載地址:http://xml.apache.org/xang 


          5.3 Slide - 內容管理框架 
          Slide是一個內容管理和集成系統,是一個內容管理底層框架。Slide提供了一個分級的結構,能將內容存儲到任意的、分布式的
          數據倉庫 。出此之外,Slide還集成了安全、鎖定、內容版本和其他一些服務?!?

          下載地址:http://jakarta.apache.org/slide 


          5.4 Struts - 基于MVC設計模式的JSP 

          Struts是采用Java Servlet/JavaServer Pages技術,開發Web應用程序的開放源碼的framework。
          采用Struts能開發出基于MVC(Model-View-Controller)設計模式的應用構架。
          Struts有如下的主要功能:
          1. 包含一個controller servlet,能將用戶的請求發送到相應的Action對象。
          2. JSP自由tag庫,并且在controller servlet中提供關聯支持,幫助開發員創建交互式表單應用。
          3. 提供了一系列實用對象:XML處理、通過Java reflection APIs自動處理JavaBeans屬性、國際化的提示和消息。
          下載地址:http://jakarta.apache.org/struts



          5.5 Jetspeed - 基于Web的組件 
          Jetspeed是實現了Enterprise Information Portal的開源軟件。Jetspeed能從Internet的縱多資源中提取信息,來幫助用戶管理大量的數據。這些信息能來自不同的內容類型,從XML到XMTP,到iCalendar這些新協議?!?

          下載地址:http://java.apache.org/jetspeed 


          5.6 Turbine - 基于Servlet的Web應用開發 

          Turbine是基于servlet的framework,使有經驗的Java開發員能快速地構建web應用。
          使用Turbine,可以通過創建使用特定服務來處理模板的Screen,來集成現有的模板技術(例如Velocity、Webmacro、Java Server Pages(JSP)、FreeMarker、Cocoon)。
          下載地址:http://java.apache.org/turbine



          5.7 各種Framework比較 

          在這些framework中,我覺得Cocoon、Struts和Turbine比較好。這三者各有所長,Cocoon是最好的XML Framework,Struts是最好的JSP Framework,Turbine是最好的Servlet Framework。


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

          6. JSP Framework - Struts介紹 
          Struts是采用Java Servlet/JavaServer Pages技術,開發Web應用程序的開放源碼的framework。 

          采用Struts能開發出基于MVC(Model-View-Controller)設計模式的應用構架?!?

          Struts有如下的主要功能: 

          1. 包含一個controller servlet,能將用戶的請求發送到相應的Action對象?!?

          2. JSP自由tag庫,并且在controller servlet中提供關聯支持,幫助開發員創建交互式表單應用?!?

          3. 提供了一系列實用對象:XML處理、通過Java reflection APIs自動處理JavaBeans屬性、國際化的提示和消息?!?

          Struts是Jakarta項目的一部分,主頁在http://jakarta.apache.org/struts. 

          Version 0.5的下載地址:http://jakarta.apache.org/builds/jakarta-struts/release/v0.5 


          6.1 1、什么是MVC模式。 
          MVC(Model/View/Controller)模式是國外用得比較多的一種設計模式,好象最早是在Smaltalk中出現。MVC包括三類對象。Model是應用對象,View是它在屏幕上的表示,Controller定義用戶界面對用戶輸入的響應方式?!?

          6.2 2、是否所有JSP應用都該采用MVC模式? 
          不一定所有的JSP應用都該采用MVC模式。但對于大型應用來說,我認為還是該采用MVC模式。不使用MVC模式,用戶界面界面設計往往將這些對象混在一起,而MVC則將它們分離以提高靈活性和復用性。 

          6.3 3、Struts中能做XML嗎,與Cocoon相比有何優點? 
          Struts把主要精力放在JSP上了。Cocoon才是專業級的XML Framework。 


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

          7. Struts的安裝 
          7.1 安裝Struts需要的軟件 

          Java Development Kit - 你需要download和install 1.2(或之后)版本的JDK。下載地址:http://java.sun.com/
          J2SE
          Servlet Container - 通常的選擇是下載Tomcat(至少是3.1版,推薦使用3.2版)。下載地址:http://jakarta.apache.org/tomcat
          Ant Build System - 如果你通過Struts源碼發布包安裝,你必須下載1.1或之后版本的ant build system。在你通過Struts來開發你自己的Web應用程序是,我也推薦使用ant來build你的應用。下載地址:http://jakarta.apache.org/ant
          Servlet API Classes - 為了編譯Structs自己,或應用程序使用Struts,你需要一個包含Servlet和JSP API對象的servlet.jar包。大多數Servlet container(例如Tomcat)已經自帶了這個文件。否則,你必需下載:http://jakarta.apache.org/builds/jakarta-servletapi
          XML Parser - Structs需要一個與Java API for XML Parsing(JAXP)規格兼容的XML處理器。我推薦使用Xerces。下載地址:http://xml.apache.org/xerces-j
          Xalan XSLT Processor - 如果你通過Structs源碼發布版來構造你的Structs系統,你必須下載和安裝1_2_D01或之后版本的Xalan XSLT處理器(Xerces中已自帶Xalan)。這個處理器用于將基于XML的Structs文檔轉換為Html文檔。



          7.2 通過源碼構造Structs 

          1.下載Structs的源碼發布包。
          2.設置ANT_HOME環境變量,指向你的Ant目錄。
          3.設置JAVA_HOME環境變量,指向你的JDK目錄。
          4.設置SERVLETAPI_HOME環境變量,指向你的Servlet API目錄(如果你的CLASSPATH已經包含了servlet.jar,就不需要指定該目錄)
          5.將Structs的源碼發布包進行解包。
          6.進入Structs目錄,運行以下命令:
             ./build.sh dist
          該命令將創建Struts的二進制發布包,目錄在../dist/structs(相對于你的編譯目錄)。



          7.3 通過Struts的二進制發布包安裝Structs 

          1.下載Struts的二進制發布版。
          2.將Struts的二進制發布版進行解包。(如果你是通過Struts源碼構造Struts,build的結果就已經是已解包的Struts)。解包后的Struts包含以下內容:
             lib/struts.jar - 這個文件包含了Struts的所有Java對象。你需要把它拷貝到你的Web應用的WEB-INF/lib目錄。
             lib/structs.tld - 這是一個"tag library descriptor"文件,它描述了Struts庫的自由tag。需要將它拷貝到你的Web應用的WEB-INF目錄。
             webapps/struts-documentation.war - 這是一個"web application archive"文件,包含了所有的Struts文檔。你可以將它安裝到支持Servlet API 2.2或之后版本的servlet container(推薦使用tomcat)中。
             webapps/struts-example.war - 這是一個web應用實例,它廣泛地演示了Struts的許多功能。你可以將它安裝到兼容Servlet2.2或之后版本以及JSP1.1或之后版本規范的servlet容器中(推薦使用tomcat)。
             webapps/struts-test.war - 這個web應用包含了Struts支持的許多tag的測試網頁,可以作為使用Struts tag的例子。

          可通過以下的步驟在你自己的應用程序中使用Struts:
          1.將Struts目錄的lib/struts.jar拷貝到web應用的WEB-INF/lib目錄。
          2.將Struts目錄的lib/struts*.tld拷貝到web應用的WEB-INF目錄。
          3.修改Web應用目錄的WEB-INF/web.xml文件,增加一個元素來定義controller servlet,增加一個元素來建立URI請求與servlet的對應關系??梢詤⒄誗truts例子中的WEB-INF/web.xml文件來了解詳細的語法要求。
          4.修改Web應用目錄的WEB-INF/web.xml文件,使之包含以下的tag庫定義:

                     /WEB-INF/struts.tld
                     /WEB-INF/struts.tld


                     /WEB-INF/struts-bean.tld
                     /WEB-INF/struts-bean.tld


                     /WEB-INF/struts-logic.tld
                     /WEB-INF/struts-logic.tld

          5.創建一個WEB-INF/action.xml文件來定義你的web應用的action映射關系??梢詤⒄誗truts例子中的action.xml文件來了解詳細的語法要求。
          6.在使用Struts tag庫的JSP網頁中加入以下tag庫定義:
                   <@ taglib uri="/WEB-INF/struts.tld" prefix="struts" %>
                   <@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
                   <@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
          7.最后,在編譯你的web應用的java程序時,不要忘了在CLASSPATH中包含struts.jar文件喲。

          posted @ 2006-08-17 19:58 Lansing 閱讀(262) | 評論 (0)編輯 收藏

          一.技術概觀

          在表現形式上,J2EE是一組規范,而.NET更象是一組產品。但它們的目的都是為了企業應用提供分布式的,高可靠性的解決方案.它們在架構上有著很多的相似之處,下表是一個簡單對照:

          J2EE .NET

          通信協議 Remote Method Invocation over Internet InterOrb Protocol (RMI/IIOP),XML

          編程語言 Java C#,VB.NET,COBOL

          運行時環境 Java Virtual Machine (JVM) Common Language Runtime (CLR)

          胖客戶端 Java Swing Windows Forms

          目錄服務 Java Naming and Directory Interface (JNDI) Active Directory Services Interface (ADSI)

          數據訪問 Java Database Connection (JDBC) ,Java Connectors ADO.NET

          異步消息處理 Java Message Service (JMS) Microsoft Message Queue

          表示層技術 Servlets, Java Server Page(JSP) ASP.NET

          中間層組件模型 EJB,JavaBean COM+,COM

          安全訪問 JAAS COM+ Security

          Call Context

          事物處理 Java Transaction Server (JTS) Microsoft Distributed Transaction Coordinator (MS-DTC)

          開發工具 WebGain Visual Café

          Borland JBuilder

          IBM VisualAge 等

          (第三方提供,規范本身沒有定義) Visual Studio.NET

          J2EE平臺的構成

          EJB - J2EE 中間層,完成商業邏輯;

          JAAS - J2EE 處理認證和授權的API;

          Java Connectors - J2EE 用于連接異種數據源的API,對上層來講是透明的;

          JSP, Java Servlets - J2EE的表示層技術,用于生成用戶界面;

          Java Virtual Machine - Java 語言運行環境;

          JDBC - J2EE數據庫訪問;

          JMS - J2EE的異步消息隊列;

          JNDI - J2EE的名字查找API,獨立于目錄服務器;

          JTS - J2EE用于處理交易的API;

          RMI/IIOP - J2EE的分布式對象的通訊API,提供了和CORBA交互的能力。

          .NET平臺構成

          .NET Framework - .NET應用運行的基礎;

          IL (Intermediary Language) - 所有的.NET語言首先被編譯成該中間語言,然后在CLR中運行;

          SOAP - 用于服務訪問的工業標準;

          DCOM - 組件間通信協議;

          MS-DTC - 用來在.NET平臺上使用兩階段提交協議來處理分布式交易;

          CLR - .NET應用的運行時環境;

          COM+ - .NET的中間層模型,用于構建商務邏輯;

          ADO.NET - .NET 對數據訪問的API。

          此外.NET平臺還包括其他一些產品象Application Center Server,BizTalk Server ,NLBS (Network Load Balancing Service),Commerce Server,Enterprise Servers,HIS (Host Integration Server),ISAS (Internet Security and Acceleration Server)用來提供象防火墻,安全訪問,B2B交易,負載平衡等服務.J2EE規范本身沒有定義這些服務,但可通過選擇第三方產品來滿足類似的要求。

          二.技術比較

          1.一 vs 多

          一種語言vs多種語言,一個平臺vs多個平臺.這似乎是大家最喜于津津樂道的話題,也似乎是所有問題的焦點。

          兩種平臺主流的開發語言Java和C#在架構上有著驚人的相似:虛擬機技術,基于沙箱的安全模型,分層的命名空間,垃圾回收等。所以從第一眼看上去,C#簡直就是Java的克隆。但微軟并不這樣認為,微軟的說明是:“它集成了C++, Java,Modula 2,C和Smalltalk等多種語言的精華,對它們共同的核心思想象深度面向對象(deep object-orientation),對象簡化 (object-simplification)等都一一做了參考。”一方面,C#的大多數關鍵字來源于C++,使它在書寫上有別于Java。但另一方面,C#的嚴格的類型轉換等概念卻明顯來自于Java(當然,它的原始類型的定義更嚴格,并且據微軟聲稱沒有影響到效率.),使其在內涵上有克隆之嫌.但即是Java,其有些特性也和Smalltalk頗有淵源.所以評價一種開發語言的優劣不僅是看其外在的表現形式,更重要的是其實實在在的功效.作為一種新語言,C#加入了基于XML的標記,可以被編譯器用來直接生成文檔,C#的另一個特點:一站式軟件(one-stop-shopping software)強調了自解釋( self-describing) 的編碼方式,即頭文件,IDL(Interface Definition Language),GUID和其他復雜的接口無需再被引用.也即是C#,VB.NET等代碼片斷可以任意的被加入到其他語言中.這無疑在多種語言混合編程的模式中是一次飛躍,但是,其難維護性也是不言而喻的。

          微軟的.NET的平臺提供了象C#,VB.NET,COBOL等多種開發語言,C#是新的,而其他的每一種語言都是在原有的基礎上改造而來.這是微軟煞費苦心并且也是不得以的要為習慣于這些語言的程序員鋪一條便捷之路.但是,這些語言的改造與其說是整容到不如說是一次開膛破肚的大手術.首先是觀念變了,Basic,Cobol等語言先天的缺少面向對象的內涵,現在卻變成了面向對象的語言,這就不是要求其傳統的程序員僅僅熟悉一些額外的關鍵字那么簡單的問題了.基于面向對象的軟件分析設計開發測試是完全不同于基于傳統過程性語言的質變,所以這一過程的轉變對傳統程序員來講也是一個痛苦和漫長的過程.在傳統程序員面前,微軟看似提供了豐富多采的解決方法,但對于實際問題而言,卻怕是有些力不從心.所以一個簡單的辦法是:直接使用C#.對于獨立軟件開發商來講,其轉換成本不容忽視.其次,在一個軟件項目中使用多種語言,開發商必須同時擁有多種語言專家和多個獨立的難以互相支援的開發小組,無疑的,這也使其軟件的維護的成本已非線性的曲線增長.多樣性是雙韌劍,實施時需仔細斟酌.

          跨平臺是J2EE的最大賣點,也是至今為止還絆住微軟的柵欄.當開發商完成了符合J2EE規范的軟件時,其客戶可以依據其喜好和實力來選擇不同應用服務器.從基于open source的免費軟件到高端滿足B2B需求的商業套件來搭建自己的平臺.但是由于J2EE的規范還不完善,各個J2EE服務器的提供商為了使其提供其各自理解的完整的功能,不得不添加一些額外的特性.這就使得使用了這些特別功能的應用軟件,綁定到了特定的應用服務器上.隨著J2EE規范的發展,這種差別會逐漸減小.

          微軟的跨平臺解決方案是Web services,它解決的是異種平臺上不同應用之間的連通性問題.從技術角度講,它除了以XML為介質之外沒有什么新意.但它的重要意義在于:它是微軟這樣一個重量級選手所推出的,前景不容小視.構造和使用 Web services 的過程較為簡單:

          服務提供者用他所選擇的語言構造服務;

          服務提供者用WSDL(the Web Services Description Language)來定義該服務;

          服務提供者在UDDI (Universal Description, Discovery, and Integration )中注冊該服務;

          使用者的應用程序從 UDDI中查找已注冊服務;

          使用者的應用程序通過 SOAP (the Simple Object Access Protocol )來調用服務.(SOAP使用HTTP來傳遞基于XML為表現形式的參數)

          正如我們所討論的: Web services解決的是異構平臺上服務連通性的問題,但在現實中所更迫切需要的是如何在異構的平臺上構造具有可擴展性,高可靠性,高可用性,故障冗余,錯誤恢復能力的企業應用.缺少這一點,從結構上講,.NET平臺還遠未完善.

          2.中間層

          基于組件的軟件開發技術可以在較高的級別上實現軟件復用,加快企業軟件開發的進程.在J2EE構架中, JavaBean和EJB(Enterprise JavaBeans) 被用來完成事物邏輯.其中EJB和 JavaBean 有著類似的模型,但它被用來創建分布式的企業應用.它定義服務器端組件的模型,具有以下一些特性:

          生存期模型;

          訪問模型;

          安全模型;

          事物處理模型;

          會話處理模型;

          數據封裝模型;

          部署模型

          根據這些模型,簡單的編碼就可完成復雜的功能。

          在微軟的.NET平臺中,舊的COM 和 COM+的組件模型被新的組件模型所代替。增加了象基于沙箱的安全模型和垃圾回收等功能.并且實現了多重接口繼承,擴展的元數據和新的代理模型等.舊有的COM和COM+組件也可被映射到新的運行環境中。

          綜上所述,兩眾架構在基于組件的中間層的設計上各有千秋,對于創建分布式的,復雜的,高效的,高可靠性的的應用程序都有著足夠的能力。

          3.表示層

          兩種架構都同時支持胖客戶端和瘦客戶端.即C/S模式和B/S模式.對于C/S模式,J2EE提供了替代Java AWT的Java Swing,同時作為可視化組件的JavaBean也可用來構造系統。對于B/S結構的表示層,J2EE使用 servlet ,JSP(Java Server Page) ,HMTL,WML,XML等工具來實現。

          微軟的胖客戶端技術則由 Windows Forms代替了MFC.它們起的作用相同,在結構上 Windows Forms 被插入到.NET的運行時框架(runtime framework)和組件模型 (component model)中.在瘦客戶模型中, ASP.NET代替了舊有的ASP和 HMTL, WML ,XML作為表示層。在 ASP.NET 中,C#,VB.NET等語言的代碼片斷可被自由引用.ASP.NET 頁面被首先轉換成中介語言( Intermediary Language),然后再被 中介語言及時編譯器(just-in-time IL compiler)編譯,最后運行于公共語言運行環境中,并且 ASP.NET 提供了頁面的緩沖,所以,其運行速度要遠遠快于ASP。

          大體上,兩種架構所使用的表示層的技術非常類似,雖在細節上各有所長,但總體功能當在伯仲之間。

          4.數據訪問

          J2EE 和 .Net 已不同的形式支持數據的訪問。JDBC和ADO一樣和所連接的數據庫無關,并且通過連接,命令語句和結果集來對數據進行操作.所以屬于中間層次的 API.更高一級的數據封裝和數據管理是通過實體EJB (entity EJB)來完成的.基于容器管理的實體EJB使開發更快捷,管理更方便.事實上,由于實體EJB的load()和store()方法的同步機制,將大大緩解因并發而使數據庫產生的瓶頸.也可以采用不屬于J2EE規范的第三方數據訪問工具,象WebGain的 TopLink。

          而微軟的.NET的數據訪問工具則由基于XML的ADO.NET代替了基于COM組件的ADO.任何以XML為輸出的數據源都可以作為 ADO.NET 的數據源.相應的結果集升級為數據集 (DataSets),命令語句則升級為數據集命令(DataSetCommands).從形式來看,微軟的ADO.NET更新潮和時髦一些,基于XML的特性使其可以處理極其豐富的數據源,并且,因其構架在HTTP協議之上,易于穿透防火墻,使溝通更為便利.但由于XML本身的基于標記的特性,很明顯限制了在有超大數據量和有網絡瓶頸的應用中的使用.而J2EE的數據訪問規則則顯得略有單薄,但同時卻更簡單,更有效.并且通過對應用程序有效的層次的設計,對于數據庫和基于XML的數據源的訪問,也是可以無縫的整合的。

          三.整體評價

          在微軟還沒有足以和Java平臺相對抗的產品的時候,微軟所樂于做是大聲的宣傳:"write once, debug everywhere"。而它的對手則更樂于這樣評價它:"微軟開始也喜歡Java,他們喜歡它的方式是讓它死去,他們當然也憎恨它,他們甚至憎恨每一個以J開頭的單詞。"但是現在,形式不同了,微軟有了足以自豪的.NET他們可以已他們自己所喜好的方式來對J2EE和.NET來做各種比較。最熱鬧的應該算是微軟出示的第三方對.NET Pet Shop和J2EE的 Pet Store的綜合比較了.有興趣的讀者可以到MSDN,www.onjava.com,IBM開發者原地等網站看到相關評論。

          J2EE .NET

          易用性 ** ***

          擴展能力 *** **

          多平臺支持 **** *

          多語言支持 * ****

          可靠性 *** ***

          性能 *** ***

          可管理性 *** ***

          重用性 **** **

          負載平衡 *** ***

          開放標準 ***** *

          就企業而言,內部眾多系統的整合、系統的延展性、安全性是更需要注意的議題,而這些都是J2EE的優勢,也是微軟的不足處。 在效率方面,J2EE陣營主張通過硬件的效能增加來彌補軟件的不足.開放標準,功能強大,易于移植這些都是J2EE的賣點。但讓人奇怪的是IBM的WebSphere和BEA的WebLogic在J2EE市場占了大半壁江山,而作為規則制定者的SUN卻在做壁上觀。

          微軟確實提供了從桌面的辦公軟件,開發工具,到后臺服務器數據庫的全方位的產品。 但統一平臺的使用者可能要犧牲跨平臺的好處,并也有可能由此就被無窮無盡的鎖定在微軟的許可證的汪洋中.更簡單,更快捷,更高效是微軟的目標,隨著時代的發展,我們也許會看到更完美的技術解決方案。

          posted @ 2006-08-17 19:45 Lansing 閱讀(324) | 評論 (0)編輯 收藏

          創建Web應用的配置文件

          對于Struts應用,它的配置文件web.xml應該對ActionServlet類進行配置,此外,還應該聲明Web應用所使用的Struts標簽庫,本例中聲明使用了三個標簽庫: Struts Bean、Struts HTML和Struts Logic標簽庫。例程1為web.xml的源代碼。

          例程1 web.xml

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

          <!DOCTYPE web-app
          PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
          "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

          < web-app >

          < display-name >
          HelloApp Struts Application
          </display-name >

          <!-- Standard Action Servlet Configuration -->

          < servlet >

          < servlet-name > action </servlet-name >

          < servlet-class >
          org.apache.struts.action.ActionServlet
          < /servlet-class >

          < init-param >
          < param-name> config< /param-name >
          < param-value>
          /WEB-INF/struts-config.xml
          </param-value >
          </init-param >

          < load-on-startup>2</load-on-startup >

          </servlet>

          <!-- Standard Action Servlet Mapping -->

          < servlet-mapping>

          < servlet-name > action</servlet-name>

          < url-pattern>*.do</url-pattern>

          </servlet-mapping>

          <!-- The Usual Welcome File List -->

          < welcome-file-list>

          < welcome-file > hello.jsp</welcome-file>

          </welcome-file-list>

          <!-- Struts Tag Library Descriptors -->

          < taglib >

          < taglib-uri >
          /WEB-INF/struts-bean.tld
          </taglib-uri>

          < taglib-location>
          /WEB-INF/struts-bean.tld
          </taglib-location>

          </taglib>

          < taglib >

          < taglib-uri >
          /WEB-INF/struts-html.tld
          </taglib-uri >

          < taglib-location >
          /WEB-INF/struts-html.tld
          </taglib-location >

          </taglib >

          < taglib >

          < taglib-uri >
          /WEB-INF/struts-logic.tld
          </taglib-uri >

          < taglib-location >
          /WEB-INF/struts-logic.tld
          </taglib-location >

          </taglib >

          </web-app >

          創建Struts框架的配置文件

          正如前面提及的,Struts框架允許把應用劃分成多個組件,提高開發速度。而Struts框架的配置文件struts-config.xml可以把這些組件組裝起來,決定如何使用它們。例程2是helloapp應用的struts-config.xml文件的源代碼。

          例程2  struts-config.xml
          <?xml version="1.0" encoding="ISO-8859-1" ?>
          <!DOCTYPE struts-config
          PUBLIC"-//Apache Software Foundation
          //DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

          <!--This is the Struts configuration file
          for the "Hello!" sample application-->
          < struts-config>
          <!-- ===== Form Bean Definitions ====== -->
          < form-beans>
          < form-bean name="HelloForm" type="hello.HelloForm"/>
          </form-beans>
          <!-- ====== Action Mapping Definitions ====== -->
          < action-mappings>
          <!-- Say Hello! -->
          < action path="/HelloWorld"
          type="hello.HelloAction"
          name="HelloForm"
          scope="request"
          validate="true"
          input="/hello.jsp"
          >
          < forward name="SayHello" path="/hello.jsp" />
          </action >
          </action-mappings >
          <!-- ===== Message Resources Definitions ===== -->
          < message-resources parameter="hello.application"/>
          </struts-config >


          以上代碼對helloapp應用的HelloForm、HelloAction和消息資源文件進行了配置,首先通過元素配置了一個ActionForm Bean,名叫HelloForm,它對應的類為hello.HelloForm:



          接著通過元素配置了一個Action組件: 
          < action
          path = "/HelloWorld"
          type ="hello.HelloAction"
          name = "HelloForm"
          scope = "request"
          validate = "true"
          input = "/hello.jsp"
          >
          < forward name="SayHello" path="/hello.jsp" />
          </action >

          元素的path屬性指定請求訪問Action的路徑,type屬性指定Action的完整類名,name屬性指定需要傳遞給Action的ActionForm Bean,scope屬性指定ActionForm Bean的存放范圍,validate屬性指定是否執行表單驗證,input屬性指定當表單驗證失敗時的轉發路徑。元素還包含一個子元素,它定義了一個請求轉發路徑。

          本例中的 元素配置了HelloAction組件,對應的類為hello.HelloAction,請求訪問路徑為"HelloWorld",當Action類被調用時,Struts框架應該把已經包含表單數據的HelloForm Bean傳給它。HelloForm Bean存放在request范圍內,并且在調用Action類之前,應該進行表單驗證。如果表單驗證失敗,請求將被轉發到接收用戶輸入的網頁hello.jsp,讓用戶糾正錯誤。

          struts-config.xml文件最后通過元素定義了一個Resource Bundle:元素的parameter屬性指定Resource Bundle使用的消息資源文件。本例中parameter屬性為"hello.application",表明消息資源文件名為"application.properties",它的存放路徑為WEB-INF/classes/hello/application.properties。

          posted @ 2006-08-17 19:43 Lansing 閱讀(335) | 評論 (0)編輯 收藏

          某些網站允許軟件開發社團通過發布開發者指南、白皮書、FAQs【常見問題解答】和源代碼以實現信息的共享。隨著信息量的增長,和幾個開發者貢獻出自己的知識庫,于是網站提供搜索引擎來搜索站點上現有的所有信息。雖然這些搜索引擎對文本文件的搜索可以做的很好,但對開發者搜索源代碼做了比較嚴格的限制。搜索引擎認為源代碼就是純文本文件,因此,在這一點上,與成熟的可以處理大量源文件的工具――grep相比沒有什么不同。

          在這篇文章中,我推薦使用Lucene,它是基于Java的開源搜索引擎,通過提取和索引相關的源碼元素來搜索源代碼。這里,我僅限定搜索Java源代碼。然而,Lucene同樣可以做到對其他編程語言的源代碼的搜索。

          文章給出了在Lucene環境下搜索引擎重點方面的簡短概述。要了解更多細節信息,參考Resources部分。

          版權聲明:任何獲得Matrix授權的網站,轉載時請務必保留以下作者信息和鏈接
          作者:Renuka;Knightchen(作者的blog:http://blog.matrix.org.cn/page/Knightchen)
          原文:http://www.matrix.org.cn/resource/article/44/44362_Lucene+Java.html
          關鍵字:Lucene;Java

          概述
          Lucene是最流行的開源搜索引擎庫之一。它由能文本索引和搜索的核心API組成。Lucene能夠對給出一組文本文件創建索引并且允許你用復雜的查詢來搜索這些索引,例如:+title:Lucene -content:Search、search AND Lucene、+search +code。在進入搜索細節之前,先讓我來介紹一下Lucene的一些功能。

          在Lucene中索引文本

          搜索引擎對所有需要被搜索的數據進行掃描并將其存儲到能有效獲取的一個結構里。這個最有名的結構被稱為倒排索引。例如,現在考慮對一組會議記錄進行索引。首先,每個會議記錄的文件被分為幾個獨立的部分或者域:如標題、作者、email、摘要和內容。其次,每一域的內容被標記化并且提取出關鍵字或者術語。這樣就可以建立如下表所示會議記錄的倒排索引。

          ????????....???????? ????????

          對于域中的每一術語而言,上圖存儲了兩方面的內容:該術語在文件中出現的數量(即頻率【DF】)以及包含該術語的每一文件的ID。對于每個術語保存的其它細節:例如術語在每個文件中出現的次數以及出現的位置也被保存起來。無論如何,對于我們非常重要的一點是要知道:利用Lucene檢索文件意味著將其保存為一種特定格式,該格式允許高效率查詢及獲取。

          分析被索引的文本

          Lucene使用分析器來處理被索引的文本。在將其存入索引之前,分析器用于將文本標記化、摘錄有關的單詞、丟棄共有的單詞、處理派生詞(把派生詞還原到詞根形式,意思是把bowling、bowler和bowls還原為bowl)和完成其它要做的處理。Lucene提供的通用分析器是:
          &#61548;????????SimpleAnalyzer:用字符串標記一組單詞并且轉化為小寫字母。
          &#61548;????????StandardAnalyzer:用字符串標記一組單詞,可識別縮寫詞、email地址、主機名稱等等。并丟棄基于英語的stop words (a, an, the, to)等、處理派生詞。

          檢索(搜索索引)
          索引結構建立后,可以通過指定被搜索的字段和術語構造復雜的查詢來對索引進行檢索。例如,用戶查詢abstract:system AND email:abc@mit.edu得到的結果是所有在摘要中包含system、在email地址中有abc@mit.edu的文件。也就是說,如果在前面倒排索引表的基礎上搜索就返回Doc15。與查詢匹配的文件是按照術語在文件中出現的次數以及包含該術語的文檔的數量進行排列的。Lucene執行一種順序排列機制并且提供了給我們更改它的彈性。

          源代碼搜索引擎

          現在我們知道了關于搜索引擎的基本要點,下面讓我們看一看用于搜索源代碼的搜索引擎應如何實現。下文中展示在搜索Java示例代碼時,開發者主要關注以下Java類:
          繼承一個具體類或實現一個接口。
          調用特定的方法。
          使用特定的Java類。

          綜合使用上述部分的組合可以滿足開發者獲取他們正在尋找相關代碼的需要。因此搜索引擎應該允許開發者對這些方面進行單個或組合查詢。IDEs【集成開發環境】有另一個局限性:大部分可使用的工具僅僅基于上述標準之一來支持搜索源代碼。在搜索中,缺乏組合這些標準進行查詢的靈活性。

          現在我們開始建立一個支持這些要求的源代碼搜索引擎。

          編寫源代碼分析器
          第一步先寫一個分析器,用來提取或去除源代碼元素,確保建立最佳的索引并且僅包含相關方面的代碼。在Java語言中的關鍵字--public,null,for,if等等,在每個.java文件中它們都出現了,這些關鍵字類似于英語中的普通單詞(the,a,an,of)。因而,分析器必須把這些關鍵字從索引中去掉。

          我們通過繼承Lucene的抽象類Analyzer來建立一個Java源代碼分析器。下面列出了JavaSourceCodeAnalyzer類的源代碼,它實現了tokenStream(String,Reader)方法。這個類定義了一組【stop words】,它們能夠在索引過程中,使用Lucene提供的StopFilter類來被去除。tokenStream方法用于檢查被索引的字段。如果該字段是“comment”,首先要利用LowerCaseTokenizer類將輸入項標記化并轉換成小寫字母,然后利用StopFilter類除去英語中的【stop words】(有限的一組英語【stop words】),再利用PorterStemFilter移除通用的語形學以及詞尾后綴。如果被索引的內容不是“comment”,那么分析器就利用LowerCaseTokenizer類將輸入項標記化并轉換成小寫字母,并且利用StopFilter類除去Java關鍵字。

          package com.infosys.lucene.code JavaSourceCodeAnalyzer.;

          import java.io.Reader;
          import java.util.Set;
          import org.apache.lucene.analysis.*;

          public class JavaSourceCodeAnalyzer extends Analyzer {
          ??????private Set javaStopSet;
          ??????private Set englishStopSet;
          ??????private static final String[] JAVA_STOP_WORDS = {
          ???????? "public","private","protected","interface",
          ????????????"abstract","implements","extends","null""new",
          ?? ????????"switch","case", "default" ,"synchronized" ,
          ????????????"do", "if", "else", "break","continue","this",
          ?? ????????"assert" ,"for","instanceof", "transient",
          ????????????"final", "static" ,"void","catch","try",
          ????????????"throws","throw","class", "finally","return",
          ????????????"const" , "native", "super","while", "import",
          ????????????"package" ,"true", "false" };
          ???? private static final String[] ENGLISH_STOP_WORDS ={
          ????????????"a", "an", "and", "are","as","at","be" "but",
          ????????????"by", "for", "if", "in", "into", "is", "it",
          ????????????"no", "not", "of", "on", "or", "s", "such",
          ????????????"that", "the", "their", "then", "there","these",
          ????????????"they", "this", "to", "was", "will", "with" };
          ???? public SourceCodeAnalyzer(){
          ????????????super();
          ????????????javaStopSet = StopFilter.makeStopSet(JAVA_STOP_WORDS);
          ????????????englishStopSet = StopFilter.makeStopSet(ENGLISH_STOP_WORDS);
          ???? }
          ???? public TokenStream tokenStream(String fieldName, Reader reader) {
          ????????????if (fieldName.equals("comment"))
          ???????????????????? return?? new PorterStemFilter(new StopFilter(
          ????????????????????????new LowerCaseTokenizer(reader),englishStopSet));
          ????????????else
          ???????????????????? return?? new StopFilter(
          ?????????????????? new LowerCaseTokenizer(reader),javaStopSet);
          ???? }
          }



          編寫類JavaSourceCodeIndexer
          第二步生成索引。用來建立索引的非常重要的類有IndexWriter、Analyzer、Document和Field。對每一個源代碼文件建立Lucene的一個Document實例。解析源代碼文件并且摘錄出與代碼相關的語法元素,主要包括:導入聲明、類名稱、所繼承的類、實現的接口、實現的方法、方法使用的參數和每個方法的代碼等。然后把這些句法元素添加到Document實例中每個獨立的Field實例中。然后使用存儲索引的IndexWriter實例將Document實例添加到索引中。

          下面列出了JavaSourceCodeIndexer類的源代碼。該類使用了JavaParser類解析Java文件和摘錄語法元素,也可以使用Eclipse3.0 ASTParser。這里就不探究JavaParser類的細節了,因為其它解析器也可以用于提取相關源碼元素。在源代碼文件提取元素的過程中,創建Filed實例并添加到Document實例中。

          import org.apache.lucene.document.*;
          import org.apache.lucene.index.*;
          import com.infosys.lucene.code.JavaParser.*;

          public class JavaSourceCodeIndexer {
          ????private static JavaParser parser = new JavaParser();
          ????????private static final String IMPLEMENTS = "implements";
          ????????private static final String IMPORT = "import";
          ????????...
          ????????public static void main(String[] args) {
          ????????????????File indexDir = new File("C:\\Lucene\\Java");
          ????????????????File dataDir = new File("C:\\JavaSourceCode ");
          ????????????????IndexWriter writer = new IndexWriter(indexDir,
          ????????????????????new JavaSourceCodeAnalyzer(), true);
          ????????????????indexDirectory(writer, dataDir);
          ????????????????writer.close();
          ????????}
          ????????public static void indexDirectory(IndexWriter writer, File dir){
          ????????????File[] files = dir.listFiles();
          ????????????for (int i = 0; i < files.length; i++) {
          ????????????????????File f = files[i];
          ????????????????// Create a Lucene Document
          ????????????????Document doc = new Document();
          ????????????????//??Use JavaParser to parse file
          ????????????????parser.setSource(f);
          ????????????????addImportDeclarations(doc, parser);
          ?????? ???????? ????????addComments(doc, parser);
          ???????? ????????// Extract Class elements Using Parser
          ????????????????JClass cls = parser.getDeclaredClass();
          ????????????????addClass(doc, cls);
          ???????? ????????// Add field to the Lucene Document
          ?????? ????????????????doc.add(Field.UnIndexed(FILENAME, f.getName()));
          ????????????????writer.addDocument(doc);
          ?? ???????? ????????}
          ????????}
          ????????private static void addClass(Document doc, JClass cls) {
          ?? ????????????????//For each class add Class Name field
          ????????????doc.add(Field.Text(CLASS, cls.className));
          ????????????String superCls = cls.superClass;
          ????????????if (superCls != null)
          ?? ????????????????//Add the class it extends as extends field
          ????????doc.add(Field.Text(EXTENDS, superCls));
          ????????????// Add interfaces it implements
          ????????????ArrayList interfaces = cls.interfaces;
          ????????????for (int i = 0; i < interfaces.size(); i++)
          ????????????????doc.add(Field.Text(IMPLEMENTS, (String) interfaces.get(i)));
          ?? ???????? ????????//Add details??on methods declared
          ????????????addMethods(cls, doc);
          ????????????ArrayList innerCls = cls.innerClasses;
          ?? ????????????????for (int i = 0; i < innerCls.size(); i++)
          ????????????????addClass(doc, (JClass) innerCls.get(i));
          ????????}
          ????????private static void addMethods(JClass cls, Document doc) {
          ????????????ArrayList methods = cls.methodDeclarations;
          ????????????for (int i = 0; i < methods.size(); i++) {
          ?????? ????????????????JMethod method = (JMethod) methods.get(i);
          ????????????????// Add method name field
          ????????????????doc.add(Field.Text(METHOD, method.methodName));
          ????????????????// Add return type field
          ????????????????doc.add(Field.Text(RETURN, method.returnType));
          ????????????????ArrayList params = method.parameters;
          ????????????????for (int k = 0; k < params.size(); k++)
          ????????????????// For each method add parameter types
          ????????????????????doc.add(Field.Text(PARAMETER, (String)params.get(k)));
          ????????????????String code = method.codeBlock;
          ????????????????if (code != null)
          ????????????????//add the method code block
          ????????????????????doc.add(Field.UnStored(CODE, code));
          ????????????}
          ????????}
          ????????private static void addImportDeclarations(Document doc, JavaParser parser) {
          ?? ????????????????ArrayList imports = parser.getImportDeclarations();
          ????????????if (imports == null)???? return;
          ????????????for (int i = 0; i < imports.size(); i++)
          ????????????????????//add import declarations as keyword
          ????????????????doc.add(Field.Keyword(IMPORT, (String) imports.get(i)));
          ????????}
          }



          Lucene有四種不同的字段類型:Keyword,UnIndexed,UnStored和Text,用于指定建立最佳索引。
          &#61548;????????Keyword字段是指不需要分析器解析但需要被編入索引并保存到索引中的部分。JavaSourceCodeIndexer類使用該字段來保存導入類的聲明。
          &#61548;????????UnIndexed字段是既不被分析也不被索引,但是要被逐字逐句的將其值保存到索引中。由于我們一般要存儲文件的位置但又很少用文件名作為關鍵字來搜索,所以用該字段來索引Java文件名。
          &#61548;????????UnStored字段和UnIndexed字段相反。該類型的Field要被分析并編入索引,但其值不會被保存到索引中。由于存儲方法的全部源代碼需要大量的空間。所以用UnStored字段來存儲被索引的方法源代碼??梢灾苯訌腏ava源文件中取出方法的源代碼,這樣作可以控制我們的索引的大小。
          &#61548;????????Text字段在索引過程中是要被分析、索引并保存的。類名是作為Text字段來保存。下表展示了JavaSourceCodeIndexer類使用Field字段的一般情況。



          1.
          ?? 用Lucene建立的索引可以用Luke預覽和修改,Luke是用于理解索引很有用的一個開源工具。圖1中是Luke工具的一張截圖,它顯示了JavaSourceCodeIndexer類建立的索引。


          圖1:在Luke中索引截圖

          如圖所見,導入類的聲明沒有標記化或分析就被保存了。類名和方法名被轉換為小寫字母后,才保存的。

          查詢Java源代碼
          建立多字段索引后,可以使用Lucene來查詢這些索引。它提供了這兩個重要類分別是IndexSearcher和QueryParser,用于搜索文件。QueryParser類則用于解析由用戶輸入的查詢表達式,同時IndexSearcher類在文件中搜索滿足查詢條件的結果。下列表格顯示了一些可能發生的查詢及它的含義:


          用戶通過索引不同的語法元素組成有效的查詢條件并搜索代碼。下面列出了用于搜索的示例代碼。

          public class JavaCodeSearch {
          public static void main(String[] args) throws Exception{
          ????File indexDir = new File(args[0]);
          ????String q =??args[1]; //parameter:JGraph code:insert
          ????Directory fsDir = FSDirectory.getDirectory(indexDir,false);
          ????IndexSearcher is = new IndexSearcher(fsDir);

          ????PerFieldAnalyzerWrapper analyzer = new
          ????????PerFieldAnalyzerWrapper( new
          ????????????????JavaSourceCodeAnalyzer());

          ????analyzer.addAnalyzer("import", new KeywordAnalyzer());
          ????Query query = QueryParser.parse(q, "code", analyzer);
          ????long start = System.currentTimeMillis();
          ????Hits hits = is.search(query);
          ????long end = System.currentTimeMillis();
          ????System.err.println("Found " + hits.length() +
          ????????????????" docs in " + (end-start) + " millisec");
          ????for(int i = 0; i < hits.length(); i++){
          ????Document doc = hits.doc(i);
          ????????System.out.println(doc.get("filename")
          ????????????????+ " with a score of " + hits.score(i));
          ????}
          ????is.close();
          }
          }



          IndexSearcher實例用FSDirectory來打開包含索引的目錄。然后使用Analyzer實例分析搜索用的查詢字符串,以確保它與索引(還原詞根,轉換小寫字母,過濾掉,等等)具有同樣的形式。為了避免在查詢時將Field作為一個關鍵字索引,Lucene做了一些限制。Lucene用Analyzer分析在QueryParser實例里傳給它的所有字段。為了解決這個問題,可以用Lucene提供的PerFieldAnalyzerWrapper類為查詢中的每個字段指定必要的分析。因此,查詢字符串import:org.w3c.* AND code:Document將用KeywordAnalyzer來解析字符串org.w3c.*并且用JavaSourceCodeAnalyzer來解析Document。QueryParser實例如果查詢沒有與之相符的字段,就使用默認的字段:code,使用PerFieldAnalyzerWrapper來分析查詢字符串,并返回分析后的Query實例。IndexSearcher實例使用Query實例并返回一個Hits實例,它包含了滿足查詢條件的文件。

          結束語

          這篇文章介紹了Lucene——文本搜索引擎,其可以通過加載分析器及多字段索引來實現源代碼搜索。文章只介紹了代碼搜索引擎的基本功能,同時在源碼檢索中使用愈加完善的分析器可以提高檢索性能并獲得更好的查詢結果。這種搜索引擎可以允許用戶在軟件開發社區搜索和共享源代碼。

          資源
          這篇文章的示例Sample code
          Matrix:http://www.matrix.org.cn
          Onjava:http://www.onjava.com/
          Lucene home page
          "Introduction to Text Indexing with Apache Jakarta Lucene:" 這是篇簡要介紹使用Lucene的文章。
          Lucene in Action: 在使用Lucene方面進行了深入地講解。

          Renuka Sindhgatta 是一位資深的構架師,現在在印度班加羅爾市【 in the Software Engineering and Technology labs of Infosys Technologies Limited 】工作。

          posted @ 2006-08-17 19:42 Lansing 閱讀(646) | 評論 (0)編輯 收藏

          J2EE簡介



          J2EE是一個開放的、基于標準的平臺,可以開發、部署和管理N層結構的、面向Web的、以服務器為中心的企業級應用,它是利用Java 2 平臺來簡化與多級企業解決方案的開發、部署和管理相關的諸多復雜問題的應用體系結構。

          J2EE平臺采用一個多層次分布式的應用模式。這意味著應用邏輯根據功能被劃分成組件,組成J2EE應用的不同應用組件安裝在不同的服務器上,這種劃分是根據應用組件屬于多層次J2EE環境中的哪一個層次來決定的。如圖1所示,J2EE應用可以由三或四個層次組成,J2EE多層次應用一般被認為是三層應用,因為它們是被分布在三個不同的地點:客戶端機器、J2EE服務器和數據庫或后端的傳統系統服務器。三層架構應用是對標準的客戶端/服務器應用架構的一種擴展, 即在客戶端應用和后臺存儲之間增加一個多線程應用服務器。



          J2EE體系包括JSP、Servlet、EJB、WEB SERVICE等多項技術。這些技術的出現給電子商務時代的WEB應用開發提供了一個非常有競爭力的選擇。怎樣把這些技術組合起來,形成一個適應項目需要的穩定架構是項目開發過程中一個非常重要的步驟。

          一個成功的軟件需要有一個成功的架構,但軟件架構的建立是一個復雜而又持續改進的過程,軟件開發者們不可能對每個不同的項目做不同的架構,而總是盡量重用以前的架構,或開發出盡量通用的架構方案,Struts就是流行的基于J2EE的架構方案之一,其他常用的基于J2EE的架構方案還有Turbine、RealMothods等。本文主要探討Struts框架技術的應用。

          J2EE應用程序架構的發展

          在J2EE應用程序架構的發展路程中,主要經歷了兩個大的階段:

          1、Model 1

          在JSP頁面中結合業務邏輯、服務器端處理程序和HTML,在JSP頁面中同時實現顯示、業務邏輯和流程控制,從而快速的完成Web應用開發。這種模型的不足之處:1)不利于應用擴展和更新。2)業務邏輯和表示邏輯混合在JSP頁面中沒有進行抽象和分離,不利于應用系統業務的重用和改動。

          2、Model 2

          表示的是基于MVC模式的框架。根據Model 2,servlet 處理數據存取和導航流, JSP處理表現。Model 2 使Java 工程師和HTML設計者分別工作于它們所擅長和負責的部分。Model 2應用的一部分發生改變并不強求其他部分也跟著發生改變。HTML 開發人員可以改變程序的外觀和感覺,并不需要改變后端servlet的工作方式。把應用邏輯、處理過程和顯示邏輯分成不同的組件實現。彌補了Model1的不足。

          Struts框架技術

          Struts 框架就是基于Model 2 的架構,也就是基于MVC模式的框架技術。它是一個免費的開源的WEB層的應用框架,具有很高的可配置性,和有一個不斷增長的特性列表。一個前端控制組件,一系列動作類,動作映射,處理XML的實用工具類,服務器端java bean 的自動填充,支持驗證的WEB 表單,國際化支持,生成HTML,實現表現邏輯和模板組成了struts的靈魂。圖2顯示了Struts組件是如何一起工作的。



          Struts 的ActionServlet 控制導航流。其他Struts 類,比如Action, 用來訪問業務邏輯類。當 ActionServlet 從容器接收到一個請求,它使用URI (或者路徑“path”) 來決定哪個Action 將用來處理請求。一個 Action可以校驗輸入,并且訪問業務層以從數據庫或其他數據服務中檢索信息。

          為校驗輸入或者使用輸入來更新數據庫, Action 需要知道什么被提交上來。并不是強制每個Action 從請求中抓取這些值,而是由 ActionServlet 將輸入綁定到JavaBean中。輸入 bean是Struts ActionForm c類的子類。ActionServlet 通過查找請求的路徑可以決定使用哪個ActionForm,Action 也是通過同樣的方法選取的。每個Action都必須以HTTP 響應進行應答。 通常, Struts Action 并不自行加工響應信息,而是將請求轉發到其他資源,比如JSP 頁面。Struts 提供一個ActionForward 類,用來將一個頁面的路徑存儲為邏輯名稱。當完成業務邏輯后,Action 選擇并向Servlet返回一個ActionForward。Servlet 然后使用存儲在ActionForward 對象中的路徑來調用頁面完成響應。

          Struts 將這些細節都綁定在一個ActionMapping 對象中。每個ActionMapping 相對于一個特定的路徑。當某個路徑被請求時,Servlet 就查詢ActionMapping 對象。ActionMapping對象告訴servlet哪個Actions、 ActionForms 和 ActionForwards 將被使用。

          所有這些細節,關于Action, ActionForm, ActionForward, ActionMapping,以及其他一些東西,都在struts-config.xml 文件中定義。 ActionServlet 在啟動時讀取這個配置文件,并創建一個配置對象數據庫。在運行時,Struts 應用根據的是文件創建的配置對象,而不是文件本身。

          基于Struts框架的應用設計實例

          本文以“面向鑄造行業的網絡化制造ASP平臺開發”項目中的軟件租用模塊為例,來說明如何設計基于Struts框架的Web應用。在該模塊中,用戶合法登陸網站后,可以根據需要選擇所要租用的軟件類型及軟件中的功能模塊,確認信息提交服務器后,用戶將收到系統給予的登陸密碼,用戶即可登陸網站,在線使用租用軟件,實行業務托管。

          根據項目需求分析,確定該系統必須具備的性能有:1)良好的交互性:工作內容中有相當大的部分是人機交流,這就要求系統的交互性要強。2)較好的可擴展性:工作的內容和形式具有多變性,要求系統具有良好的可擴展性。3)良好的可維護性:系統投入使用后,主要是由管理員承擔系統維護的工作,維護人員不定期變動,這就要求系統的可維護性強。4)具有較好的跨平臺性:用戶可能使用各種不同的操作系統,而且為了適應今后可能的變化,系統應具有較好的跨平臺性?;谝陨纤狞c,在開發軟件租用模塊時,采用J2EE編程環境,并相應采用了專為J2EE定制的Struts框架。

          做基于Struts框架的項目開發,關鍵是要有一個好的整體模型,計劃好系統中包括哪幾個模塊,每個模塊各需要什么樣的FormBean、JavaBean,各種處理結果都通過哪些JSP頁面來展現,同時配置好struts-config.xml文件。本系統的設計模型如圖3所示。



          ActionServlet接受所有的HTTP請求,然后根據配置文件的內容,決定將請求映射到哪一個Action對象,本系統中有兩個Action對象,分別對應著登陸遠程軟件(LogonAction)和系統反饋密碼(MailAction)。

          LogonAction首先會驗證用戶是否已經登錄,如果沒有登錄則重定向到登錄頁面(Logon.jsp),驗證通過后根據請求參數決定下一步的處理,如果用戶還沒有選擇租用軟件,則轉到軟件介紹租用界面(Query.jsp),選擇需要租用的軟件或軟件的某些模塊,提交信息后,MailAction使服務器向用戶提交密碼,用戶接收到密碼后,登陸運行軟件。

          如果用戶登陸軟件成功,則通過配置文件struts-config.xml中的ActionForward,通過GetInfo對象把該用戶租用的軟件信息讀取道FormBean中,然后調用JSP頁面顯示Bean里的數據。如果是保存數據信息,則調SaveInfo對象將FormBean里保持的信息存入數據庫;如果是修改信息,則調ModifyInfo對象將FormBean里保持的修改后的信息存入數據庫;如果是刪除數據信息,則調用DeleteInfo對象將FormBean里保持的信息從數據庫中刪除。

          經過這樣設計的系統,用戶界面和數據處理已經完全分離,再加上在JSP頁面中使用了自定義標記,使頁面中沒有了Java的腳本代碼,這樣Web界面的設計和后端程序的編寫就有了清晰的界線,便于開發團隊的分工,并且維護起來也很方便。

          結束語

          Struts是一種非常優秀的基于J2EE的MVC應用框架,雖然從正式發布到現在也只有兩年多的時間,但它已經越來越多地運用于企業平臺之上,許多大型網站已成功地應用了Struts框架。本文在總結了Struts框架技術及其工作原理的基礎上,結合“面向鑄造行業的網絡化制造ASP平臺開發”項目,提出了在線租用模塊的設計思路,這為今后更好的應用采用Struts框架提供了參考。

          posted @ 2006-08-17 19:36 Lansing 閱讀(1227) | 評論 (1)編輯 收藏

          構建高性能的J2EE應用不但需要了解常用的實施技巧。下面介紹最常用的10種有效方法,可幫助架構設計師們快速成為這方面的專家。

          Java性能的基礎—內存管理

          任何Java應用,單機的或J2EE的性能基礎都可歸結到你的應用是如何管理內存的問題。Java的內存管理包括兩個重要任務:內存的分配和內存的回收。在內存的分配中,目標是要減少需要創建的對象。

          內存回收是導致性能下降的普遍原因。也就是說,內存中的對象越多,垃圾回收越困難。所以我們對創建對象的態度應該越保守越好。

          在J2EE應用中常見的兩個內存有關的問題是:游離的對象(也被稱為內存泄露)和對象循環(指大量頻繁創建和刪除-在Java中體現為解除引用---對象)。

          我們應注意確保所有可到達的對象實際是活的,即這些對象不但在內存中,而且也要在執行的代碼中是存在的。當對象在應用中已經沒有用了,而我們卻忘記了刪除對該對象的引用時,游離的對象就出現了。

          我們知道垃圾回收會占用CPU時間。短期對象的大量創建增加了垃圾回收的頻率會造成性能下降。

          不要在Servlet中實現業務邏輯

          在構建J2EE應用時,架構工程師通常會使用到J2EE的基本部分——Servlet。如果架構師不使用Session Beans, Entity Beans, 或 Message Beans, 那么改進性能的方法就很少。只能采用增加CPU或更多的物理服務器等方法。EJB使用了緩存(cache)和資源池等方法可以提高性能和擴展性。

          盡可能使用本地接口訪問EJB

          在早期的J2EE (遵循EJB1.X規范)應用中,訪問EJB是`通過RMI使用遠程接口實現的。隨著EJB2.0的出現,可以通過本地接口訪問EJB,不再使用RMI,在同一個JVM中使用遠程方法已經少多了。但是現在還是有一些使用EJB1.X實現的應用和不知道使用本地接口的一些EJB新手。為說明這點,我們作個比較:

          1、客戶端應用調用本地Stub

          2、該Stub裝配參數

          3、該Stub傳到skeleton

          4、該skeleton分解參數

          5、該skeleton調用EJB對象

          6、EJB對象執行容器服務

          7、EJB對象調用企業BEAN實例

          8、企業BEA執行操作

          9、執行組裝/分解步驟然后返回

          與遠程接口處理相比較,本地接口的EJB方法是:

          1、客戶端調用本地對象

          2、本地對象執行容器服務

          3、本地對象調用企業Bean實例

          4、企業Bean實例執行操作

          5、沒有其他返回步驟!

          如果你不需要從遠程的客戶端訪問一個特殊EJB,就應該使用本地方法。

          在實現Session Bean的服務中封裝對實體EJB的訪問

          從Servlet訪問實體EJB不但效率低而且難于維護。使用Session Facade(會話外觀)模式可把對實體EJB的訪問封裝在會話EJB中,在該會話EJB中通過使用本地接口訪問實體EJB而避免過多的遠程調用。

          這項技術會有額外的性能和擴展方面的好處,這是因為會話和實體EJB可以使用緩存和資源池技術來進行改進。另外,由于負載的需要,會話和實體EJB可被擴展部署到其他硬件設備上,這比將Servlet層復制擴展到其他硬件設備上要簡單的多。

          盡量粗粒度訪問遠程EJB

          當訪問遠程EJB時,調用set/get方法將產生過多的網絡請求,同時也導致遠程接口處理的過載。為避免這種情況,可考慮將數據屬性集中在一個對象中,這樣通過一次對遠程EJB的調用就可以傳遞所有數據。這項技術就是數據傳輸對象(Data Transfer Object)模式。

          優化SQL

          J2EE的架構設計工程師和開發人員通常不是SQL專家或經驗豐富的數據庫管理員。首先應該確保SQL使用了數據庫提供的索引支持。在某些情況下,將數據庫的索引和數據分開存放會提高性能。但要知道,增加額外的索引可以提高SELECT性能但也會降低INSERT的性能。對于某些數據庫,關聯表之間的排序會嚴重影響性能??梢远嘞驍祿旃芾韱T咨詢。

          避免在實體EJB中過多執行SQL

          有時候,通過實體EJB訪問數據會執行多個SQL語句。根據J2EE 規范,第一步,將調用實體Bean的find(發現)方法;第二步,在第一次調用實體EJB的業務方法時,容器會調用ejbLoad()從數據庫中獲得信息。

          很多CMP(容器管理持久性)在調用發現方法時就緩存了實體數據,所以在調用ejbLoad()時就不再訪問數據庫了。應該避免使用BMP(Bean管理的持久性)或者自己實現緩存算法避免二次訪問數據庫。

          使用Fast Lane Reader 模式訪問只讀數據

          J2EE應用經常要以只讀方式訪問大量長時間不變的數據,而不是訪問單個實體,例如瀏覽在線產品目錄。在這種只讀情況下,使用實體EJB訪問數據會導致嚴重過載并且實現很麻煩。實體EJB 適合于對單個實體的粗粒度訪問,訪問大量的列表只讀數據時效率不高。不管是使用CMP還是BMP,一定需要編寫代碼操作多個實體EJB及其關聯。這將導致訪問多個數據庫并存在大量的也是不必要的事務開銷。

          利用Java Messaging Servce(消息服務)

          J2EE規范在JMS中提供了內置的異步處理服務。當涉及到系統需求時,應該了解在什么情況下應該采用JMS進行異步處理的設計。一旦確定要執行一些異步處理,那么同步處理的任務就應該越少越好,將數據庫密集的操作安排在稍后的異步處理中完成。

          緩存JNDI Lookup查找

          很多操作在進行JNDI查找時要消耗大量資源。通常應該緩存JNDI資源避免網絡調用和某些處理的過載。可以緩存的JNDI查找包括:

          EJB Home Interfaces

          Data Sources

          JMS Connection Factories

          MS Destinations/Topics

          一些JNDI包實現了緩存功能。但是調用對EJB主接口的narrow方法時,這種功能作用有限。緩存查找的設計應該使用共享的IntialContext實例,盡管構建它很麻煩。這是因為需要訪問多種數據源,包括應用資源文件JNDI.properties,系統屬性的各項參數,傳入到構造函數的各項參數。

          posted @ 2006-08-17 19:35 Lansing 閱讀(240) | 評論 (0)編輯 收藏

          Java語言內置了synchronized關鍵字用于對多線程進行同步,大大方便了Java中多線程程序的編寫。但是僅僅使用synchronized關鍵字還不能滿足對多線程進行同步的所有需要。大家知道,synchronized僅僅能夠對方法或者代碼塊進行同步,如果我們一個應用需要跨越多個方法進行同步,synchroinzed就不能勝任了。在C++中有很多同步機制,比如信號量、互斥體、臨屆區等。在Java中也可以在synchronized語言特性的基礎上,在更高層次構建這樣的同步工具,以方便我們的使用。
          ????當前,廣為使用的是由Doug?Lea編寫的一個Java中同步的工具包,可以在這兒了解更多這個包的詳細情況:
          ????http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
          ????該工具包已經作為JSR166正處于JCP的控制下,即將作為JDK1.5的正式組成部分。本文并不打算詳細剖析這個工具包,而是對多種同步機制的一個介紹,同時給出這類同步機制的實例實現,這并不是工業級的實現。但其中會參考Doug?Lea的這個同步包中的工業級實現的一些代碼片斷。
          ????本例中還沿用上篇中的Account類,不過我們這兒編寫一個新的ATM類來模擬自動提款機,通過一個ATMTester的類,生成10個ATM線程,同時對John賬戶進行查詢、提款和存款操作。Account類做了一些改動,以便適應本篇的需要:

          1. import ?java.util.HashMap;
          2. import ?java.util.Map;
          3. class ?Account?{
          4. ????String?name;
          5. ????//float?amount;
          6. ????
          7. ????//使用一個Map模擬持久存儲
          8. ????static?Map?storage?=?new?HashMap();
          9. ????static?{
          10. ????????storage.put("John",?new?Float(1000.0f));
          11. ????????storage.put("Mike",?new?Float(800.0f));
          12. ????}????
          13. ????
          14. ????
          15. ????public?Account(String?name)?{
          16. ????????//System.out.println("new?account:"?+?name);
          17. ????????this.name?=?name;
          18. ????????//this.amount?=?((Float)storage.get(name)).floatValue();
          19. ????}
          20. ????public?synchronized?void?deposit(float?amt)?{
          21. ????????float?amount?=?((Float)storage.get(name)).floatValue();
          22. ????????storage.put(name,?new?Float(amount?+?amt));
          23. ????}
          24. ????public?synchronized?void?withdraw(float?amt)?throws?InsufficientBalanceException?{
          25. ????????float?amount?=?((Float)storage.get(name)).floatValue();
          26. ????????if?(amount?>=?amt)
          27. ????????????amount?-=?amt;
          28. ????????else?
          29. ????????????throw?new?InsufficientBalanceException();
          30. ????????????????
          31. ????????storage.put(name,?new?Float(amount));
          32. ????}
          33. ????public?float?getBalance()?{
          34. ????????float?amount?=?((Float)storage.get(name)).floatValue();
          35. ????????return?amount;
          36. ????}
          37. }



          在新的Account類中,我們采用一個HashMap來存儲賬戶信息。Account由ATM類通過login登錄后使用:

          1. public ?class?ATM?{
          2. ????Account?acc;
          3. ????
          4. ????//作為演示,省略了密碼驗證
          5. ????public?boolean?login(String?name)?{
          6. ????????if?(acc?!=?null)
          7. ????????????throw?new?IllegalArgumentException("Already?logged?in!");
          8. ????????acc?=?new?Account(name);
          9. ????????return?true;
          10. ????}
          11. ????
          12. ????public?void?deposit(float?amt)?{
          13. ????????acc.deposit(amt);
          14. ????}
          15. ????
          16. ????public?void?withdraw(float?amt)?throws?InsufficientBalanceException??{
          17. ????????????acc.withdraw(amt);
          18. ????}
          19. ????
          20. ????public?float?getBalance()?{
          21. ????????return?acc.getBalance();
          22. ????}
          23. ????
          24. ????public?void?logout?()?{
          25. ????????acc?=?null;
          26. ????}
          27. ????
          28. }
          29. 下面是ATMTester,在ATMTester中首先生成了10個ATM實例,然后啟動10個線程,同時登錄John的賬戶,先查詢余額,然后,再提取余額的80%,然后再存入等額的款(以維持最終的余額的不變)。按照我們的預想,應該不會發生金額不足的問題。首先看代碼:

            1. public ?class?ATMTester?{
            2. ????private?static?final?int?NUM_OF_ATM?=?10;
            3. ????public?static?void?main(String[]?args)?{
            4. ????????ATMTester?tester?=?new?ATMTester();
            5. ????????
            6. ????????final?Thread?thread[]?=?new?Thread[NUM_OF_ATM];
            7. ????????final?ATM?atm[]?=?new?ATM[NUM_OF_ATM];
            8. ????????for?(int?i=0;?i
            9. ????????????atm[i]?=?new?ATM();
            10. ????????????thread[i]?=?new?Thread(tester.new?Runner(atm[i]));
            11. ????????????thread[i].start();
            12. ????????}????
            13. ????????
            14. ????}
            15. ????
            16. ????class?Runner?implements?Runnable?{
            17. ????????ATM?atm;
            18. ????????
            19. ????????Runner(ATM?atm)?{
            20. ????????????this.atm?=?atm;
            21. ????????}
            22. ????????
            23. ????????public?void?run()?{
            24. ????????????atm.login("John");
            25. ????????????//查詢余額
            26. ????????????float?bal?=?atm.getBalance();
            27. ????????????try?{
            28. ????????????????Thread.sleep(1);?//模擬人從查詢到取款之間的間隔
            29. ????????????}?catch?(InterruptedException?e)?{
            30. ????????????????//?ignore?it
            31. ????????????}?
            32. ????????????
            33. ????????????try?{
            34. ????????????????System.out.println("Your?balance?is:"?+?bal);
            35. ????????????????System.out.println("withdraw:"?+?bal?*?0.8f);
            36. ????????????????atm.withdraw(bal?*?0.8f);
            37. ????????????????System.out.println("deposit:"?+?bal?*?0.8f);
            38. ????????????????atm.deposit(bal?*?0.8f);
            39. ????????????}?catch?(InsufficientBalanceException?e1)?{
            40. ????????????????System.out.println("余額不足!");
            41. ????????????}?finally?{
            42. ????????????????????????????????????atm.logout();
            43. ???????????????????????????}
            44. ????????}
            45. ????}
            46. }


            運行ATMTester,結果如下(每次運行結果都有所差異):

            Your?balance?is:1000.0
            withdraw:800.0
            deposit:800.0
            Your?balance?is:1000.0
            Your?balance?is:1000.0
            withdraw:800.0
            withdraw:800.0
            余額不足!
            Your?balance?is:200.0
            Your?balance?is:200.0
            Your?balance?is:200.0
            余額不足!
            Your?balance?is:200.0
            Your?balance?is:200.0
            Your?balance?is:200.0
            Your?balance?is:200.0
            withdraw:160.0
            withdraw:160.0
            withdraw:160.0
            withdraw:160.0
            withdraw:160.0
            withdraw:160.0
            withdraw:160.0
            deposit:160.0
            余額不足!
            余額不足!
            余額不足!
            余額不足!
            余額不足!
            余額不足!

            為什么會出現這樣的情況?因為我們這兒是多個ATM同時對同一賬戶進行操作,比如一個ATM查詢出了余額為1000,第二個ATM也查詢出了余額1000,然后兩者都期望提取出800,那么只有第1個用戶能夠成功提出,因為在第1個提出800后,賬戶真實的余額就只有200了,而第二個用戶仍認為余額為1000。這個問題是由于多個ATM同時對同一個賬戶進行操作所不可避免產生的后果。要解決這個問題,就必須限制同一個賬戶在某一時刻,只能由一個ATM進行操作。如何才能做到這一點?直接通過synchronized關鍵字可以嗎?非常遺憾!因為我們現在需要對整個Account的多個方法進行同步,這是跨越多個方法的,而synchronized僅能對方法或者代碼塊進行同步。在下一篇我們將通過編寫一個鎖對象達到這個目的。

          我們首先開發一個BusyFlag的類,類似于C++中的Simaphore。

          1. public ?class?BusyFlag?{
          2. ????protected?Thread?busyflag?=?null;
          3. ????protected?int?busycount?=?0;
          4. ????
          5. ????public?synchronized?void?getBusyFlag()?{
          6. ????????while?(tryGetBusyFlag()?==?false)?{
          7. ????????????try?{
          8. ????????????????wait();
          9. ????????????}?catch?(Exception?e)?{}????????????
          10. ????????}
          11. ????}
          12. ????
          13. ????private?synchronized?boolean?tryGetBusyFlag()?{
          14. ????????if?(busyflag?==?null)?{
          15. ????????????busyflag?=?Thread.currentThread();
          16. ????????????busycount?=?1;
          17. ????????????return?true;
          18. ????????}
          19. ????????
          20. ????????if?(busyflag?==?Thread.currentThread())?{
          21. ????????????busycount++;
          22. ????????????return?true;
          23. ????????}
          24. ????????return?false;????????
          25. ????}
          26. ????
          27. ????public?synchronized?void?freeBusyFlag()?{
          28. ????????if(getOwner()==?Thread.currentThread())?{
          29. ????????????busycount--;
          30. ????????????if(busycount==0)?{
          31. ????????????????busyflag?=?null;
          32. ?????????????????????????????????????notify();
          33. ????????????????????????????}
          34. ????????}
          35. ????}
          36. ????
          37. ????public?synchronized?Thread?getOwner()?{
          38. ????????return?busyflag;
          39. ????}
          40. }


          注:參考Scott?Oaks?&?Henry?Wong《Java?Thread》

          BusyFlag有3個公開方法:getBusyFlag,?freeBusyFlag,?getOwner,分別用于獲取忙標志、釋放忙標志和獲取當前占用忙標志的線程。使用這個BusyFlag也非常地簡單,只需要在需要鎖定的地方,調用BusyFlag的getBusyFlag(),在對鎖定的資源使用完畢時,再調用改BusyFlag的freeBusyFlag()即可。下面我們開始改造上篇中的Account和ATM類,并應用BusyFlag工具類使得同時只有一個線程能夠訪問同一個賬戶的目標得以實現。首先,要改造Account類,在Account中內置了一個BusyFlag對象,并通過此標志對象對Account進行鎖定和解鎖:

          1. import ?java.util.Collections;
          2. import ?java.util.HashMap;
          3. import ?java.util.Map;
          4. class ?Account?{
          5. ????String?name;
          6. ????//float?amount;
          7. ????
          8. ????BusyFlag?flag?=?new?BusyFlag();
          9. ????
          10. ????//使用一個Map模擬持久存儲
          11. ????static?Map?storage?=?new?HashMap();
          12. ????static?{
          13. ????????storage.put("John",?new?Float(1000.0f));
          14. ????????storage.put("Mike",?new?Float(800.0f));
          15. ????}
          16. ????
          17. ????static?Map?accounts?=?Collections.synchronizedMap(new?HashMap());????
          18. ????
          19. ????
          20. ????private?Account(String?name)?{
          21. ????????this.name?=?name;
          22. ????????//this.amount?=?((Float)storage.get(name)).floatValue();
          23. ????}
          24. ????
          25. ????public?synchronized?static?Account?getAccount?(String?name)?{
          26. ????????if?(accounts.get(name)?==?null)
          27. ????????????accounts.put(name,?new?Account(name));
          28. ????????return?(Account)?accounts.get(name);
          29. ????}
          30. ????public?synchronized?void?deposit(float?amt)?{
          31. ????????float?amount?=?((Float)storage.get(name)).floatValue();
          32. ????????storage.put(name,?new?Float(amount?+?amt));
          33. ????}
          34. ????public?synchronized?void?withdraw(float?amt)?throws?InsufficientBalanceException?{
          35. ????????float?amount?=?((Float)storage.get(name)).floatValue();
          36. ????????if?(amount?>=?amt)
          37. ????????????amount?-=?amt;
          38. ????????else?
          39. ????????????throw?new?InsufficientBalanceException();
          40. ????????????????
          41. ????????storage.put(name,?new?Float(amount));
          42. ????}
          43. ????public?float?getBalance()?{
          44. ????????float?amount?=?((Float)storage.get(name)).floatValue();
          45. ????????return?amount;
          46. ????}
          47. ????
          48. ????public?void?lock()?{
          49. ????????flag.getBusyFlag();
          50. ????}
          51. ????
          52. ????public?void?unlock()?{
          53. ????????flag.freeBusyFlag();
          54. ????}
          55. }

          新的Account提供了兩個用于鎖定的方法:lock()和unlock(),供Account對象的客戶端在需要時鎖定Account和解鎖Account,Account通過委托給BusyFlag來提供這個機制。另外,大家也發現了,新的Account中提供了對Account對象的緩存,同時去除了public的構造方法,改為使用一個靜態工廠方法供用戶獲取Account的實例,這樣做也是有必要的,因為我們希望所有的ATM機同時只能有一個能夠對同一個Account進行操作,我們在Account上的鎖定是對一個特定Account對象進行加鎖,如果多個ATM同時實例化多個同一個user的Account對象,那么仍然可以同時操作同一個賬戶。所以,要使用這種機制就必須保證Account對象在系統中的唯一性,所以,這兒使用一個Account的緩存,并將Account的構造方法變為私有的。你也可以說,通過在Account類鎖上進行同步,即將Account中的BusyFlag對象聲明為static的,但這樣就使同時只能有一臺ATM機進行操作了。這樣,在一臺ATM機在操作時,全市其它的所有的ATM機都必須等待。
          另外必須注意的一點是:Account中的getAccount()方法必須同步,否則,將有可能生成多個Account對象,因為可能多個線程同時到達這個方法,并監測到accounts中沒有“John”的Account實例,從而實例化多個John的Account實例。s

          ATM類只需作少量改動,在login方法中鎖定Account,在logout方法中解鎖:

          1. public ?class?ATM?{
          2. ????Account?acc;
          3. ????
          4. ????//作為演示,省略了密碼驗證
          5. ????public?synchronized?boolean?login(String?name)?{
          6. ????????if?(acc?!=?null)
          7. ????????????throw?new?IllegalArgumentException("Already?logged?in!");
          8. ????????acc?=?Account.getAccount(name);
          9. ????????acc.lock();
          10. ????????return?true;
          11. ????}
          12. ????
          13. ????public?void?deposit(float?amt)?{
          14. ????????acc.deposit(amt);
          15. ????}
          16. ????
          17. ????public?void?withdraw(float?amt)?throws?InsufficientBalanceException??{
          18. ????????????acc.withdraw(amt);
          19. ????}
          20. ????
          21. ????public?float?getBalance()?{
          22. ????????return?acc.getBalance();
          23. ????}
          24. ????
          25. ????public?synchronized?void?logout?()?{
          26. ????????acc.unlock();
          27. ????????acc?=?null;
          28. ????}
          29. ????
          30. }



          ATMTester類不需要做任何修改即可同樣運行,同時保證同一個Account同時只能由一個ATM進行操作。解決了上篇提到的多個ATM同時對同一個Account進行操作造成的問題。

          在最新的Doug?Lea的util.concurrent工具包中(現處于JSR166)提供了類似的并發實用類:ReentrantLock,它實現了java?.util.concurrent.locks.Lock接口(將在JDK1.5中發布),它的作用也類似于我們這兒的BusyFlag,實現機制、使用方法也相似。但這是一個工業強度的可重入鎖的實現類。在ReentrantLock的API文檔中有它的使用示例:

          1. ?????Lock?l?=?...;?
          2. ?????l.lock();
          3. ?????try?{
          4. ?????????//?access?the?resource?protected?by?this?lock
          5. ?????}?finally?{
          6. ?????????l.unlock();
          7. ?????}
          posted @ 2006-08-17 19:30 Lansing 閱讀(494) | 評論 (0)編輯 收藏
          對象關系映射(Object Relative Mapping)簡稱ORM,是面向對象開發的一個熱點,用來解決JDBC開發中手動進行OR映射的繁雜與不便。EJB中的實體Bean在這個領域是很著名的——既因為它的先進而著名,也因為它的低效而著名。有過實體Bean開發經驗的人可能都會為實現遠程接口造成的效率低下而頭痛,在很多不大不小的項目中,使用實體Bean是否得不償失,爭論很大。一個輕量級的持久化方案也許能夠解決一些問題,Hibernate應此而生。

          ?  Hibernate是一個中間層,它的目的是把數據庫中的關系通過一定的規則映射成為對象,讓Java開發人員不用太多的考慮底層數據庫的問題,只需要像通常情況下管理對象一樣的管理數據。在關系數據庫仍將持續占據市場的情況下,它很可觀。在數據持久化領域,即便是輕量級的方案也會是復雜饒舌的,也許如同周杰倫的音樂一樣不知所云。在學習它之前,最好先回想一下以前進行數據庫開發中遇到的問題和不便,想想為什么需要一個持久化層,才能知道很多操作的目的是什么,以及為什么要這么干,在這個問題上我不想做更多的敘述,因為“長久以來……”這樣的句式通常long(不好意思,打不出來)長,會對我的鍵盤和熱情造成很大的磨損。如果讓我寫一本書,那么我會樂意去敘述什么是數據持久化,它有什么好處等等。廢話少說,來了。

          ?  首先需要配置環境,下載Hibernate 2.1(www.hibernate.org),把lib下的*.jar添加到classpath,你的數據庫JDBC驅動程序也應該在classpath中。打開hibernate.properties,針對你使用的數據庫,配置相應的信息,比如我使用的是MS SQL Server,配置如下:

          ?## MS SQL Server

          ?hibernate.dialect net.sf.hibernate.dialect.SQLServerDialect
          ?hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver
          ?hibernate.connection.url jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=zizz
          ?hibernate.connection.username sa
          ?hibernate.connection.password

          ?  其中很大部分是已經寫好的,只需要取掉注釋即可,我自己只是修改了數據庫名稱、帳號、密碼。建立一個名為zizz的數據庫備用。

          ?  然后把這個文件拷貝到你的應用的根目錄下。

          ?  我們談論了很多次映射,應該首先來看看這個映射是如何完成的。假設一個最簡單的應用,寫一個功能最單一的留言板,設計的數據有留言的編號、留言者名稱、留言內容,還有留言時間。足夠簡單吧,換做是你打算怎么干?我猜你要首先建立一個數據庫表格,名字也許叫做guestbook。No,這不是面向對象的方式,不妨首先從對象的角度來考慮。我們當然希望每一條留言都以對象的方式呈現,每個對象應該具有的屬性有:id、author、content、time。偷個懶,沒有畫UML。下面這個類應該是很容易理解的:

          ?//GuestBook.java
          ?package org.bromon.zizz;

          ?import java.util.*;

          ?public class GuestBook
          ?{
          ?private int id;
          ?private String author;
          ?private String content;
          ?private Calendar time;

          ?private void setId(int id)
          ?{
          ? this.id=id;
          ?}
          ?public int getId()
          ?{
          ? return(id);
          ?}

          ?public void setAuthor(String author)
          ?{
          ? this.author=author;
          ?}
          ?public String getAuthro()
          ?{
          ? return(author);
          ?}

          ?public void setContent(String content)
          ?{
          ? this.content=content;
          ?}
          ?public String getContent()
          ?{
          ? return(content);
          ?}

          ?public void setTime(Calendar time)
          ?{
          ? this.time=time;
          ?}
          ?public Calendar getTime()
          ?{
          ? return(time);
          ?}
          ?}


          ?  基本上是最簡單的Bean了,如果覺得困難的話,請你先回火星等我。

          ?  需要注意的是setId方法被指定為private,這是因為我希望用這個字段做主鍵,它最好由系統自動生成,所以不應該由用戶來指定,這個方法專為Hibernate準備,所以是私有的。

          ?  如何把這個類與數據庫映射起來?看看Hibernate的魔法,使用一個XML文件來描述,它應該被命名為GuestBook.hbm.xml:

          ?&lt ?xml version="1.0"? &gt
          ?&lt !DOCTYPE hibernate-mapping PUBLIC
          ??????? "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          ??????? "' target=_blank &gthttp://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" &gt

          ?&lt hibernate-mapping package="org.bromon.zizz" &gt
          ??? &lt class name="GuestBook" table=”guestbook" lazy="true" &gt
          ??????? &lt id name="id" type="integer" unsaved-value="null" &gt
          ?? &lt column name="id" sql-type="int" not-null="true"/ &gt
          ?? &lt generator class="identity"/ &gt
          ? &lt /id &gt
          ???????
          ? &lt property name="author" column="author" not-null="true" unique="false"/ &gt
          ?&lt property name="content" column="content" not-null="true"/ &gt
          ? &lt property name="time" column="time" not-null="true"/ &gt
          ??? &lt /class &gt
          ?&lt /hibernate-mapping &gt

          ?雖然有點陌生,但是很易讀,仔細琢磨一下。

          ?下面來編寫我們的應用,它的功能是插入數據:

          ?//Operate.java
          ?package org.bromon.zizz;
          ?import net.sf.hibernate.*;
          ?import net.sf.hibernate.cfg.*;
          ?import net.sf.hibernate.tool.hbm2ddl.*;
          ?import java.util.*;

          ?public class Operate
          ?{
          ?public static void main(String args[])
          ?{
          ? try
          ? {
          ?? Configuration cfg=new Configuration().addClass(GuestBook.class);
          ?? SessionFactory sessions=cfg.buildSessionFactory();
          ?? new SchemaExport(cfg).create(true,true);
          ?? Session session=sessions.openSession();
          ??
          ?? GuestBook gb=new GuestBook();
          ?? gb.setAuthor(“Bromon”);
          ?? gb.setContent(“留言的內容”);
          ?? gb.setTime(Calendar.getInstance());
          ??
          ?? Transaction ts=session.beginTransaction();
          ?? session.save(gb);
          ?? ts.commit();
          ?? session.close();
          ? }catch(Exception e)
          ? {
          ?? System.out.println(e);
          ? }
          ?}
          ?}
          ?  編譯吧:javac –d . *.java
          ?  執行一下:java org.bromon.zizz.Operate

          ?到數據庫里面看看,表格已經建立好了,并且數據也已經保存。如果把

          ?new SchemaExport().create(true,true);

          ?注釋掉,那么系統不會創建表格,而只是在已有的表格中添加新的記錄,當然,如果表格不存在的話,會產生異常。

          ?你已經看到了Hibernate神奇魔法的5%,它足夠的復雜強大,可以讓你應付復雜的應用。

          one-to-one關系
          ?在絕大多數系統當中不可能只存在一個數據表格,否則就違背了關系數據庫的初衷。表與表的關系比較復雜,可以分為幾種情況:

          ?● 一對一關聯(one to one)
          ?● 一對多關聯(one to many)
          ?● 多對一關聯(many to one)
          ?● 多對多關聯(many to many)

          ?按順序來講。假設一個一對一關聯的例子是:
          ?表格:person
          ?id 編號(主鍵)
          ?name 姓名
          ?email email地址

          ?表格:spouse
          ?id 編號(外鍵)
          ?name 姓名

          ?person這個表保存用戶信息,而spouse保存用戶配偶的信息。在一般情況下一個人只有一個配偶,這很適合我們一對一的情況。如果你對婚外戀感興趣的話,我們可以在一對多和多對一的關聯中討論這個問題,也許還可以在多對多中^_^(禽獸!)。

          ?OK,下面設計POJO:
          ?Person這個類非常簡單:

          ?/*
          ?* Created on 2004-4-19
          ?*/
          ?package org.bromon.zizz;

          ?/**
          ?* @author Bromon
          ?*/
          ?public class Person
          ?{
          ?private int id;
          ?private String name;
          ?private String email;

          ?public void setId(int id)
          ?{
          ? this.id=id;
          ?}
          ?public int getId()
          ?{
          ? return(id);
          ?}

          ?public void setName(String name)
          ?{
          ? this.name=name;
          ?}
          ?public String getName()
          ?{
          ? return(name);
          ?}

          ?public void setEmail(String email)
          ?{
          ? this.email=email;
          ?}
          ?public String getEmail()
          ?{
          ? return(email);
          ?}
          ?}


          ?然后編寫它的映射規則,這個應該能夠理解了:
          ?&lt ?xml version="1.0"? &gt
          ?&lt !DOCTYPE hibernate-mapping PUBLIC
          ?"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          ?"' target=_blank &gthttp://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" &gt?

          ?&lt hibernate-mapping package="org.bromon.zizz" &gt
          ?&lt class name="Person" table="person" lazy="true" &gt
          ?&lt id name="id" type="integer" unsaved-value="null" &gt
          ?&lt column name="id" sql-type="int" not-null="true"/ &gt
          ?&lt generator class="identity"/ &gt
          ?&lt /id &gt

          ?&lt property name="name" column="name" not-null="true" unique="false"/ &gt
          ?&lt property name="email" column="email" not-null="false"/ &gt
          ?&lt /class &gt
          ?&lt /hibernate-mapping &gt

          ?so easy是不是?一切都按部就班。下面是Souse類:

          ?/*
          ?* Created on 2004-4-20
          ?*/
          ?package org.bromon.zizz;

          ?/**
          ?* @author Bromon
          ?*/
          ?public class Spouse
          ?{
          ?private int id;
          ?private String name;
          ?private Person person;

          ?public void setId(int id)
          ?{
          ? this.id=id;
          ?}
          ?public int getId()
          ?{
          ? return(id);
          ?}

          ?public void setName(String name)
          ?{
          ? this.name=name;
          ?}
          ?public String getName()
          ?{
          ? return(name);
          ?}

          ?public void setPerson(Person person)
          ?{
          ? this.person=person;
          ?}
          ?public Person getPerson()
          ?{
          ? return(person);
          ?}
          ?}


          ?注意里面的域person。它的映射文件:

          ?&lt ?xml version="1.0"? &gt
          ?&lt !DOCTYPE hibernate-mapping PUBLIC
          ?"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          ?"' target=_blank &gthttp://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" &gt?

          ?&lt hibernate-mapping package="org.bromon.zizz" &gt
          ?&lt class name="Spouse" table="spouse" lazy="true" &gt
          ?&lt id name="id" type="integer" unsaved-value="null" &gt
          ?&lt column name="id" sql-type="int" not-null="true"/ &gt
          ?&lt generator class="foreign" &gt
          ?&lt param name="property" &gtperson&lt /param &gt
          ?&lt /generator &gt
          ?&lt /id &gt

          ?&lt property name="name" column="name" not-null="true" unique="false"/ &gt
          ?&lt one-to-one name="person" class="Person" cascade="all" constrained="true" / &gt
          ?&lt /class &gt
          ?&lt /hibernate-mapping &gt

          ?這里指明了id的generator是一個外鍵,和person相關聯。然后指定一個one-to-one關系,不難理解是不是?Hibernate的確很符合我們的思維習慣。需要提醒的是,這種關聯關系是單向的,Person并不需要去指定Spouse。

          ?下面來操作這兩個類:

          ?/*
          ?* Created on 2004-4-20
          ?*/
          ?package org.bromon.zizz;
          ?import net.sf.hibernate.*;
          ?import net.sf.hibernate.cfg.*;
          ?import net.sf.hibernate.tool.hbm2ddl.*;
          ?/**
          ?* @author Bromon
          ?*/
          ?public class OperateSpouse
          ?{
          ?public static void main(String args[])
          ?{
          ? try
          ? {
          ?? Configuration cfg=new Configuration().addClass(Spouse.class);
          ?? cfg.addClass(Person.class);
          ?? SessionFactory factory=cfg.buildSessionFactory();
          ?? new SchemaExport(cfg).create(true,true);
          ?? Session session=factory.openSession();
          ?
          ?? Person person=new Person();
          ?? person.setName("bromon");
          ?? person.setEmail("bromon@163.com");
          ?
          ?? Spouse spouse=new Spouse();
          ?? spouse.setName("who");
          ?? spouse.setPerson(person);
          ??
          ?? Transaction ts=session.beginTransaction();
          ?? session.save(person);
          ?? session.save(spouse);
          ?? ts.commit();
          ?? session.close();
          ? }catch(Exception e)
          ? {
          ?? System.out.println(e);
          ? }
          ?}
          ?}


          ?這個例子和第一篇中的例子非常相似。OK,執行一下,然后看看zizz數據庫,搞掂。

          Many-to-One關系

          ?很明顯一對多或者多對一關系是關系數據庫中非常常見的現象,下面通過父親-兒子的例子來演示一對多關系,多對一關系是類似的,不過在我們的這個例子中不宜采用,否則會帶來倫理學上的問題。

          ?首先定義Child類:
          ?/*
          ? * Created on 2004-5-8
          ? */
          ?package org.bromon.zizz;

          ?/**
          ? * @author Bromon
          ? */
          ?public class Child
          ?{
          ? private int id;
          ? private String name;
          ? private int fatherId;
          ? private Person father;

          ? public Child(){}
          ?
          ? /**
          ?? * @return
          ?? */
          ? public Person getFather()
          ? {
          ?? return father;
          ? }

          ? /**
          ?? * @return
          ?? */
          ? public int getFatherId()
          ? {
          ?? return fatherId;
          ? }

          ? /**
          ?? * @return
          ?? */
          ? public int getId()
          ? {
          ?? return id;
          ? }

          ? /**
          ?? * @return
          ?? */
          ? public String getName()
          ? {
          ?? return name;
          ? }

          ? /**
          ?? * @param person
          ?? */
          ? public void setFather(Person p)
          ? {
          ?? father = p;
          ? }

          ? /**
          ?? * @param i
          ?? */
          ? public void setFatherId(int i)
          ? {
          ?? fatherId = i;
          ? }

          ? /**
          ?? * @param i
          ?? */
          ? public void setId(int i)
          ? {
          ?? id = i;
          ? }

          ? /**
          ?? * @param string
          ?? */
          ? public void setName(String string)
          ? {
          ?? name = string;
          ? }

          ?}

          ?這里的fatherId是外鍵,關聯person表的id字段。

          ?下面是映射文件Child.hbm.xml:
          ?&lt ?xml version="1.0"? &gt
          ?&lt !DOCTYPE hibernate-mapping PUBLIC
          ??????? "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          ??????? "' target=_blank &gthttp://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" &gt?

          ?&lt hibernate-mapping package="org.bromon.zizz" &gt
          ? &lt class name="Child" table="child" lazy="true" &gt
          ?? &lt id name="id" type="integer" unsaved-value="null" &gt
          ??? &lt column name="id" sql-type="int" not-null="true"/ &gt
          ??? &lt generator class="identity"/ &gt
          ?? &lt /id &gt
          ???????
          ?? &lt property name="name" column="name" not-null="true" unique="false"/ &gt
          ?? &lt many-to-one name="father" column="fatherid" / &gt
          ??????
          ? &lt /class &gt
          ?&lt /hibernate-mapping &gt
          ?需要注意的是fatherId并沒有做為一個property被映射,而是在many-to-one聲明中使用。

          ?需要對Person..java做修改,添加以下代碼:

          ?import java.util.*;

          ?private Set children=new HashSet();
          ?/**
          ?* @return
          ?*/
          ?public Set getChildren()
          ?{
          ? return children;
          ?}
          ?/**
          ?* @param set
          ?*/
          ?public void setChildren(Set set)
          ?{
          ? children = set;
          ?}

          ?然后修改Person.hbm.xml,對添加的代碼做映射:

          ?&lt set name="books" lazy="true" inverse="true" cascade="all"? &gt
          ? &lt key column="fatherid"/ &gt
          ? &lt one-to-many class="Child" / &gt
          ?&lt /set &gt

          ?這里的key column是child表的外鍵,inverse需要指定為true。

          ?下面做操作一下,功能是查詢person表中id=1的記錄,作為小孩的父親,然后給child表添加一條新記錄。

          ?/*
          ? * Created on 2004-5-8
          ? */
          ?package org.bromon.zizz;
          ?import net.sf.hibernate.*;
          ?import net.sf.hibernate.cfg.*;
          ?import net.sf.hibernate.tool.hbm2ddl.*;
          ?/**
          ? * @author Bromon
          ? */
          ?public class OperateChild
          ?{
          ? /**
          ?? * @param args
          ?? */
          ? public static void main(String args[])
          ? {
          ?? try
          ?? {
          ??? Configuration cfg = new Configuration().addClass(Person.class);
          ??? cfg.addClass(Child.class);
          ??? SessionFactory sessions = cfg.buildSessionFactory();
          ??? new SchemaExport(cfg).create(true, true);
          ??? Session session = sessions.openSession();
          ???
          ??? Child c=new Child();
          ???
          ??? /*Query q=session.createQuery("from org.bromon.zizz.Person as p where p.id=1");
          ??? Person p=(Person)q.list().get(0);*/
          ???
          ??? Person p=(Person)session.find("from org.bromon.zizz.Person as p where p.id=?",new Integer(1),Hibernate.INTEGER).get(0);
          ??? System.out.println(p.getName());
          ??? c.setName("andy");
          ??? c.setFather(p);
          ???
          ??? Transaction ts = session.beginTransaction();
          ??? session.save(c);
          ??? ts.commit();
          ??? session.close();
          ?? } catch (Exception e)
          ?? {
          ??? System.out.println(e);
          ?? }
          ? }
          ?}

          ?被注釋掉的部分是HQL的另外一種查詢方法。在這個例子中可以看出對象的查詢非常容易,不需要自己再去封裝數據,修改和刪除對象也很容易:

          ?//得到一個對象
          ?Query q=session.createQuery("from org.bromon.zizz.Person as p where p.id=1");
          ?Person p=(Person)q.list().get(0);

          ?//修改數據
          ?p.setName(“Mr Smith”);

          ?//保存數據
          ?session.save(p);
          ?session.flush();

          ?//刪除數據
          ?session.delete(p);
          ?session.flush();

          posted @ 2006-08-17 19:26 Lansing 閱讀(304) | 評論 (0)編輯 收藏

          Alt+左箭頭,右箭頭????????以在編輯窗口切換標簽
          Alt+上下箭頭,????????????????以自動選擇鼠標所在行,并將其上下移動
          Ctrl+f6????????????????????????????可以彈出菜單,上面列出可以切換的編輯窗口,這樣不用鼠標也可切換
          Ctrl+f7????????????????????????????可以在視圖之間切換?,如編輯視圖,輸出視圖,工程視圖
          Ctrl+f8????????????????????????????可以在不同的觀察視圖中切換,就是在java視圖,調試視圖,等之間切換
          Ctrl+m????????????????????????????可以在最大化當前窗口和還原當前窗口之間切換
          Ctrl+e??????????????????????????????彈出輸入窗口,可以輸入你想要編輯的代碼窗口,和Ctrl+f6的功能相同,只不過一個是選擇的方式,一個是輸入的方式,切換窗口
          Ctrl+T??????????????????????????????可以直接顯示光標所在內容的類圖,可以直接輸入,并跳到輸入內容部分
          按住Ctrl鍵,然后鼠標指向變量名,方法名,類名???????在源代碼中快速跳轉?
          Ctrl?+?F11??????????????????????快速執行程序
          Ctrl+Shift+F???????????????????程序代碼自動排版
          Ctrl+Shift+O?????????????????自動加入引用。說明:?假設我們沒有Import任何類別時,當我們在程序里打入:?ResourceAttirbute?ra?=new?ResourceAttribute();??Eclipse會提示說沒有引用類別,這時我們只要按下Ctrl+Shift+O?,它就會自動幫我們Import這個類別。?非常方便
          Ctrl+/????????????????????????????將選取的塊注釋起來:在Debug時很方便。?
          Alt?+?/???????????????????????????就是大家都應該最常用的代碼輔助了
          Ctrl+h???????????????????????????搜索,打開搜索對話框
          Ctrl+Shift+Space??????????參數提示,如果此時位于方法體中,就會出現方法的參數提示,當前光標所在位置的參數會用粗體顯示

          作用域?功能?快捷鍵?
          全局?查找并替換?Ctrl+F?
          文本編輯器?查找上一個?Ctrl+Shift+K?
          文本編輯器?查找下一個?Ctrl+K?
          全局?撤銷?Ctrl+Z?
          全局?復制?Ctrl+C?
          全局?恢復上一個選擇?Alt+Shift+↓?
          全局?剪切?Ctrl+X?
          全局?快速修正?Ctrl1+1?
          全局?內容輔助?Alt+/?
          全局?全部選中?Ctrl+A?
          全局?刪除?Delete?
          全局?上下文信息?Alt+?
          Alt+Shift+?
          Ctrl+Shift+Space?
          Java編輯器?顯示工具提示描述?F2?
          Java編輯器?選擇封裝元素?Alt+Shift+↑?
          Java編輯器?選擇上一個元素?Alt+Shift+←?
          Java編輯器?選擇下一個元素?Alt+Shift+→?
          文本編輯器?增量查找?Ctrl+J?
          文本編輯器?增量逆向查找?Ctrl+Shift+J?
          全局?粘貼?Ctrl+V?
          全局?重做?Ctrl+Y?


          查看
          作用域?功能?快捷鍵?
          全局?放大?Ctrl+=?
          全局?縮小?Ctrl+-?


          窗口
          作用域?功能?快捷鍵?
          全局?激活編輯器?F12?
          全局?切換編輯器?Ctrl+Shift+W?
          全局?上一個編輯器?Ctrl+Shift+F6?
          全局?上一個視圖?Ctrl+Shift+F7?
          全局?上一個透視圖?Ctrl+Shift+F8?
          全局?下一個編輯器?Ctrl+F6?
          全局?下一個視圖?Ctrl+F7?
          全局?下一個透視圖?Ctrl+F8?
          文本編輯器?顯示標尺上下文菜單?Ctrl+W?
          全局?顯示視圖菜單?Ctrl+F10?
          全局?顯示系統菜單?Alt+-?


          導航
          作用域?功能?快捷鍵?
          Java編輯器?打開結構?Ctrl+F3?
          全局?打開類型?Ctrl+Shift+T?
          全局?打開類型層次結構?F4?
          全局?打開聲明?F3?
          全局?打開外部javadoc?Shift+F2?
          全局?打開資源?Ctrl+Shift+R?
          全局?后退歷史記錄?Alt+←?
          全局?前進歷史記錄?Alt+→?
          全局?上一個?Ctrl+,?
          全局?下一個?Ctrl+.?
          Java編輯器?顯示大綱?Ctrl+O?
          全局?在層次結構中打開類型?Ctrl+Shift+H?
          全局?轉至匹配的括號?Ctrl+Shift+P?
          全局?轉至上一個編輯位置?Ctrl+Q?
          Java編輯器?轉至上一個成員?Ctrl+Shift+↑?
          Java編輯器?轉至下一個成員?Ctrl+Shift+↓?
          文本編輯器?轉至行?Ctrl+L?


          搜索
          作用域?功能?快捷鍵?
          全局?出現在文件中?Ctrl+Shift+U?
          全局?打開搜索對話框?Ctrl+H?
          全局?工作區中的聲明?Ctrl+G?
          全局?工作區中的引用?Ctrl+Shift+G?


          文本編輯
          作用域?功能?快捷鍵?
          文本編輯器?改寫切換?Insert?
          文本編輯器?上滾行?Ctrl+↑?
          文本編輯器?下滾行?Ctrl+↓?


          文件
          作用域?功能?快捷鍵?
          全局?保存?Ctrl+X?
          Ctrl+S?
          全局?打印?Ctrl+P?
          全局?關閉?Ctrl+F4?
          全局?全部保存?Ctrl+Shift+S?
          全局?全部關閉?Ctrl+Shift+F4?
          全局?屬性?Alt+Enter?
          全局?新建?Ctrl+N?


          項目
          作用域?功能?快捷鍵?
          全局?全部構建?Ctrl+B?


          源代碼
          作用域?功能?快捷鍵?
          Java編輯器?格式化?Ctrl+Shift+F?
          Java編輯器?取消注釋?Ctrl+\?
          Java編輯器?注釋?Ctrl+/?
          Java編輯器?添加導入?Ctrl+Shift+M?
          Java編輯器?組織導入?Ctrl+Shift+O?
          Java編輯器?使用try/catch塊來包圍?未設置,太常用了,所以在這里列出,建議自己設置。
          也可以使用Ctrl+1自動修正。?


          運行
          作用域?功能?快捷鍵?
          全局?單步返回?F7?
          全局?單步跳過?F6?
          全局?單步跳入?F5?
          全局?單步跳入選擇?Ctrl+F5?
          全局?調試上次啟動?F11?
          全局?繼續?F8?
          全局?使用過濾器單步執行?Shift+F5?
          全局?添加/去除斷點?Ctrl+Shift+B?
          全局?顯示?Ctrl+D?
          全局?運行上次啟動?Ctrl+F11?
          全局?運行至行?Ctrl+R?
          全局?執行?Ctrl+U?


          重構
          作用域?功能?快捷鍵?
          全局?撤銷重構?Alt+Shift+Z?
          全局?抽取方法?Alt+Shift+M?
          全局?抽取局部變量?Alt+Shift+L?
          全局?內聯?Alt+Shift+I?
          全局?移動?Alt+Shift+V?
          全局?重命名?Alt+Shift+R?
          全局?重做?Alt+Shift+Y?

          熱鍵篇:Template:Alt?+?/修改處:窗口->喜好設定->工作臺->按鍵->編輯->內容輔助。個人習慣:Shift+SPACE(空白)。簡易說明:編輯程序代碼時,打sysout?+Template啟動鍵,就會自動出現:System.out.println();?。設定Template的格式:窗口->喜好設定->Java->編輯器->模板。程序代碼自動排版:Ctrl+Shift+F修改處:窗口->喜好設定->工作臺->按鍵->程序代碼->格式。個人習慣:Alt+Z。自動排版設定:窗口->喜好設定->Java->程序代碼格式制作程序。樣式頁面->將插入tab(而非空格鍵)以內縮,該選項取消勾選,下面空格數目填4,這樣在自動編排時會以空格4作縮排。快速執行程序:Ctrl?+?F11個人習慣:ALT+X修改處:窗口->喜好設定->工作臺->按鍵->執行->啟動前一次的啟動作業。簡易說明:第一次執行時,它會詢問您執行模式,設置好后,以后只要按這個熱鍵,它就會快速執行。
          <ALT+Z(排版完)、ATL+X(執行)>..我覺得很順手^___^自動匯入所需要的類別:Ctrl+Shift+O簡易說明:假設我們沒有Import任何類別時,當我們在程序里打入:

          BufferedReader?buf?=
          new?BufferedReader(new?InputStreamReader(System.in));

          此時Eclipse會警示說沒有匯入類別,這時我們只要按下Ctrl+Shift+O,它就會自動幫我們Import類別。查看使用類別的原始碼:Ctrl+鼠標左鍵點擊簡易說明:可以看到您所使用類別的原始碼。將選取的文字批注起來:Ctrl+/簡易說明:Debug時很方便。修改處:窗口->喜好設定->工作臺->按鍵->程序代碼->批注視景切換:Ctrl+F8個人習慣:Alt+S。修改處:窗口->喜好設定->工作臺->按鍵->窗口->下一個視景。簡易說明:可以方便我們快速切換編輯、除錯等視景。密技篇:一套Eclipse可同時切換,英文、繁體、簡體顯示:
          1.首先要先安裝完中文化包。
          2.在桌面的快捷方式后面加上參數即可,英文->?-nl?"zh_US"繁體->?-nl?"zh_TW"簡體->?-nl?"zh_CN"。
          (其它語系以此類推)像我2.1.2中文化后,我在我桌面的Eclipse快捷方式加入參數-n1?"zh_US"。
          "C:\Program?Files\eclipse\eclipse.exe"?-n?"zh_US"接口就會變回英文語系嚕。利用Eclipse,在Word編輯文書時可不必將程序代碼重新編排:將Eclipse程序編輯區的程序代碼整個復制下來(Ctrl+C),直接貼(Ctrl+V)到
          Word或WordPad上,您將會發現在Word里的程序代碼格式,跟Eclipse所設定的完全一樣,包括字型、縮排、關鍵詞顏色。我曾試過JBuilder、GEL、NetBeans...使用復制貼上時,只有縮排格式一樣,字型、顏色等都不會改變。外掛篇:外掛安裝:將外掛包下載回來后,將其解壓縮后,您會發現features、
          plugins這2個數據夾,將里面的東西都復制或移動到Eclipse的features、plugins數據夾內后,重新啟動Eclipse即可。讓Eclipse可以像JBuilderX一樣使用拖拉方式建構GUI的外掛:
          1.Jigloo?SWT/Swing?GUI?Builder?:http://cloudgarden.com/jigloo/index.html下載此版本:Jigloo?plugin?for?Eclipse?(using?Java?1.4?or?1.5)安裝后即可由檔案->新建->其它->GUI?Form選取要建構的GUI類型。

          2.Eclipse?Visual?Editor?Project:http://www.eclipse.org/vep/點選下方Download?Page,再點選Latest?Release?0.5.0進入下載。除了VE-runtime-0.5.0.zip要下載外,以下這2個也要:
          EMF?build?1.1.1:?(build?page)?(download?zip)?
          GEF?Build?2.1.2:?(build?page)?(download?zip)?

          3.0?M8版本,請下載:
          EMF?build?I200403250631
          GEF?Build?I20040330
          VE-runtime-1.0M1安裝成功后,便可由File->New->Visual?Class開始UI設計。安裝成功后,即可由新建->Java->AWT與Swing里選擇所要建構的GUI類型開始進行設計。VE必須配合著對應版本,才能正常使用,否則即使安裝成功,使用上仍會有問題。使用Eclipse來開發JSP程序:外掛名稱:lomboz(下載頁面)http://forge.objectweb.org/project/showfiles.php?group_id=97請選擇適合自己版本的lomboz下載,lomboz.212.p1.zip表示2.1.2版,
          lomboz.3m7.zip表示M7版本....以此類推。
          lomboz安裝以及設置教學:Eclipse開發JSP-教學文件

          Java轉exe篇:實現方式:Eclipse搭配JSmooth(免費)。
          1.先由Eclipse制作包含Manifest的JAR。制作教學
          2.使用JSmooth將做好的JAR包裝成EXE。
          JSmooth下載頁面:http://jsmooth.sourceforge.net/index.php
          3.制作完成的exe文件,可在有裝置JRE的Windows上執行。

          Eclipse-Java編輯器最佳設定:編輯器字型設定:工作臺->字型->Java編輯器文字字型。
          (建議設定Courier?New?-regular?10)編輯器相關設定:窗口->喜好設定->Java->編輯器外觀:顯示行號、強調對稱顯示的方括號、強調顯示現行行、顯示打印邊距,將其勾選,Tab寬度設4,打印編距字段設80。程序代碼協助:采預設即可。語法:可設定關鍵詞、字符串等等的顯示顏色。附注:采預設即可。輸入:全部字段都勾選。浮動說明:采預設即可。導覽:采預設即可。使自動排版排出來的效果,最符合Java設計慣例的設定:自動排版設定:窗口->喜好設定->Java->程序代碼制作格式。換行:全部不勾選。分行:行長度上限設:80。樣式:只將強制轉型后插入空白勾選。內縮空格數目:設為4。

          1.?Control-Shift-T:?打開類型(Open?type)。如果你不是有意磨洋工,還是忘記通過源碼樹(source?tree)打開的方式吧。

          2.?Control-Shift-R:?打開資源(不只是用來尋找Java文件)。小提示:利用Navigator視圖的黃色雙向箭頭按鈕讓你的編輯窗口和導航器相關聯。這會讓你打開的文件對應顯示在導航器的層級結構中,這樣便于組織信息。如果這影響了速度,就關掉它。

          3.?F3:?打開申明(Open?declaration)?;蛘?,利用Declaration?Tab(在Java視圖模式下,選擇Windows?-->?Show?View?--?>?Declaration)。當你選中代碼中的一個方法,然后按這個按鍵,它會把整個方法在申明方框里顯示出來。

          4.?Alt-left?arrow:?在導航歷史記錄(Navigation?History)中后退。就像Web瀏覽器的后退按鈕一樣,在利用F3跳轉之后,特別有用。(用來返回原先編譯的地方)

          5.?Alt-right?arrow:?導航歷史記錄中向前。

          6.?Control-Q:?回到最后依次編輯的地方。這個快捷鍵也是當你在代碼中跳轉后用的。特別是當你鉆的過深,忘記你最初在做什么的時候。

          7.?Control-Shift-G:?在workspace中搜索引用(reference)。這是重構的前提。對于方法,這個熱鍵的作用和F3恰好相反。它使你在方法的棧中,向上找出一個方法的所有調用者。一個與此相關的功能是開啟“標記”功能(occurrence?marking)?。選擇Windows->Preferences->Java->?Editor->?Mark?Occurrences,勾選選項。這時,當你單擊一個元素的時候,代碼中所有該元素存在的地方都會被高亮顯示。我個人只使用“標記本地變量”(Mark?Local?Variables)。注意:太多的高亮顯示會拖慢Eclipse。

          8.?Control-Shift-F:?根據代碼風格設定重新格式化代碼。我們的團隊有統一的代碼格式,我們把它放在我們的wiki上。要這么做,我們打開Eclipse,選擇Window?Preferences?Java?Code?Style,然后設置Code?Formatter,Code?Style和Organize?Imports。利用導出(Export)功能來生成配置文件。我們把這些配置文件放在wiki上,然后團隊里的每個人都導入到自己的Eclipse中。

          9.?Control-O:?快速概要(quick?outline)。通過這個快捷鍵,你可以迅速的跳到一個方法或者屬性,只需要輸入名字的頭幾個字母。?

          10.?Control-/:?對一行注釋或取消注釋。對于多行也同樣適用。

          11.?Control-Alt-down?arrow:?復制高亮顯示的一行或多行。

          12.?Alt-down?arrow:?將一行或多行向下移動。Alt-up?arrow會向上移動。

          其他的熱鍵在菜單里有。你可以通過按下Control-Shift-L(從3.1版本開始),看到所有快捷鍵的列表。按下Control-Shift-L兩次,會顯示熱鍵對話框(Keys?Preferences?dialog),你可以在這里自己設置熱鍵。我歡迎你在Talkback部分發表你的Eclipse提示。


          Ctrl+1 快速修復(最經典的快捷鍵,就不用多說了)

          Ctrl+D: 刪除當前行

          Ctrl+Alt+↓ 復制當前行到下一行(復制增加)

          Ctrl+Alt+↑ 復制當前行到上一行(復制增加)

          Alt+↓ 當前行和下面一行交互位置(特別實用,可以省去先剪切,再粘貼了)

          Alt+↑ 當前行和上面一行交互位置(同上)

          Alt+← 前一個編輯的頁面

          Alt+→ 下一個編輯的頁面(當然是針對上面那條來說了)

          Alt+Enter 顯示當前選擇資源(工程,or 文件 or文件)的屬性

          Shift+Enter 在當前行的下一行插入空行(這時鼠標可以在當前行的任一位置,不一定是最后)

          Shift+Ctrl+Enter 在當前行插入空行(原理同上條)

          Ctrl+Q 定位到最后編輯的地方

          Ctrl+L 定位在某行 (對于程序超過100的人就有福音了)

          Ctrl+M 最大化當前的Edit或View (再按則反之)

          Ctrl+/ 注釋當前行,再按則取消注釋

          Ctrl+O 快速顯示 OutLine

          Ctrl+T 快速顯示當前類的繼承結構

          Ctrl+W 關閉當前Editer

          Ctrl+K 參照選中的Word快速定位到下一個

          Ctrl+E 快速顯示當前Editer的下拉列表(如果當前頁面沒有顯示的用黑體表示)

          Ctrl+/(小鍵盤) 折疊當前類中的所有代碼

          Ctrl+×(小鍵盤) 展開當前類中的所有代碼

          Ctrl+Space 代碼助手完成一些代碼的插入(但一般和輸入法有沖突,可以修改輸入法的熱鍵,也可以暫用Alt+/來代替)

          Ctrl+Shift+E 顯示管理當前打開的所有的View的管理器(可以選擇關閉,激活等操作)

          Ctrl+J 正向增量查找(按下Ctrl+J后,你所輸入的每個字母編輯器都提供快速匹配定位到某個單詞,如果沒有,則在stutes line中顯示沒有找到了,查一個單詞時,特別實用,這個功能Idea兩年前就有了)

          Ctrl+Shift+J 反向增量查找(和上條相同,只不過是從后往前查)

          Ctrl+Shift+F4 關閉所有打開的Editer

          Ctrl+Shift+X 把當前選中的文本全部變味小寫

          Ctrl+Shift+Y 把當前選中的文本全部變為小寫

          Ctrl+Shift+F 格式化當前代碼

          Ctrl+Shift+P 定位到對于的匹配符(譬如{}) (從前面定位后面時,光標要在匹配符里面,后面到前面,則反之)

          下面的快捷鍵是重構里面常用的,本人就自己喜歡且常用的整理一下(注:一般重構的快捷鍵都是Alt+Shift開頭的了)

          Alt+Shift+R 重命名 (是我自己最愛用的一個了,尤其是變量和類的Rename,比手工方法能節省很多勞動力)

          Alt+Shift+M 抽取方法 (這是重構里面最常用的方法之一了,尤其是對一大堆泥團代碼有用)

          Alt+Shift+C 修改函數結構(比較實用,有N個函數調用了這個方法,修改一次搞定)

          Alt+Shift+L 抽取本地變量( 可以直接把一些魔法數字和字符串抽取成一個變量,尤其是多處調用的時候)

          Alt+Shift+F 把Class中的local變量變為field變量 (比較實用的功能)

          Alt+Shift+I 合并變量(可能這樣說有點不妥Inline)

          Alt+Shift+V 移動函數和變量(不怎么常用)

          Alt+Shift+Z 重構的后悔藥(Undo)


          經常用到的Eclipse快捷鍵
          存盤?Ctrl+s(一定記住)
          注釋代碼?Ctrl+/
          取消注釋?Ctrl+\(Eclipse3已經都合并到Ctrl+/了)
          代碼輔助?Alt+/
          快速修復?Ctrl+1
          代碼格式化?Ctrl+Shift+f
          整理導入?Ctrl+Shift+o
          切換窗口?Ctrl+f6<可改為ctrl+tab方便>
          ctrl+shift+M?導入未引用的包
          ctrl+w?關閉單個窗口
          F3?跳轉到類、變量的聲明
          F11?運行上次程序
          Ctrl?+?F11?調試上次程序
          Alt?+?回下一個編輯點
          ctrl+shift+T?查找工程中的類

          posted @ 2006-08-17 14:17 Lansing 閱讀(3684) | 評論 (0)編輯 收藏
          僅列出標題
          共4頁: 上一頁 1 2 3 4 下一頁 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          歡迎探討,努力學習Java哈

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          Lansing's Download

          Lansing's Link

          我的博客

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 莒南县| 磐石市| 汤阴县| 化隆| 蒙阴县| 芮城县| 丹寨县| 鹿泉市| 腾冲县| 太原市| 涡阳县| 西平县| 攀枝花市| 邯郸市| 霍州市| 河津市| 称多县| 北京市| 丹凤县| 大新县| 济阳县| 秀山| 白玉县| 上杭县| 离岛区| 屯昌县| 定陶县| 应用必备| 黔西县| 怀柔区| 建宁县| 太白县| 旅游| 渑池县| 平安县| 榆社县| 集贤县| 崇仁县| 崇阳县| 云安县| 孝昌县|