您的位置:首页 > 移动开发

Expresso使用说明

2005-11-28 08:52 519 查看
Expresso使用说明

修订历史记录
日期
[/b]
版本
[/b]
说明
[/b]
作者
[/b]
2005-07-04
1.0
初建
唐家平
1 简介... 2
2 引入框架开发的目的... 2
3 安装与配置 2
3.1 有两种安装方法 2
3.2 配置expresso-config.xml 2
3.3 国际/本地化问题 3
4 Expresso功能列表... 3
5 最佳实践... 3
5.1 创建包 3
5.2 创建一个Schema对象 4
5.3 创建一些需要的数据(DB)对象 4
5.4 创建一些需要的控制器(Controller)对象 5
5.5 创建一些需要的工作任务(Job)对象 10
5.6 安装Expresso应用 10
5.6.1 在config目录里创建XML配置文件 10
5.6.2 注册Schema和创建/初始化数据库 10
6 Expresso专题 11
6.1 数据对象 11
6.2 控制器对象 11
6.3 初始化Expresso为Java Application环境 12
6.4 DBTool和DBCreate. 12
6.5 数据库连接池 12
7 使用Expresso框架后工作划分... 12
7.1 分析和设计人员(包括数据库设计) 12
7.2 美工、界面设计人员 12
7.3 程序员 12
8 Expresso和Spring+Hiberate组合结构的比较 13
9 开发Expresso建议... 13
10 参考资料 14

[/b]

1 简介

Expresso是jcorporate提供的一Java开源项目,项目组主要的收入来源是出售该项目的服务支持(目前每年的服务支持费是$999.00US)。Expresso基于Struts,也就是说Struts是它的核心思想。随Expresso的安装包里,expresso/doc提供了完整的文档。最新版本的软件包可以从如下网址获得:http://www.jcorporate.com

2 引入框架开发的目的

总结起来,目的大概如下三条:1. 规范化开发结构;2. 提供大多数项目均需要的服务功能,如日志、持久层管理等;3. 提供开发工具和方法,以加快开发速度。没有结构不成方圆,程序设计从最初的机器语言发展为结构化的高级语言,从面向过程发展为面向对象,其内在原因就是由于开发的规模在急剧扩大。我们可以采用各种方法实现我们的软件项目,可是没有组织好的上千万行代码将带来的结果是可读性极低、可扩展性极差。“项目的开发象一头巨兽陷在泥潭,越陷越深。”软件需求变幻无穷,计划没有变化快,但是我们还是要寻找出不变的东西,并将它和变化的东西分离开来,框架就是这一思想的成果。

3 安装与配置

3.1 有两种安装方法

解压下载来的expresso5.0.5.zip或expresso5-0-5-src.zip或expresso5.0.5.war均能得到一个Expresso的应用,也就是开发环境;解压下载来的expresso5-0-5-complete.zip将得到一个带有Tomcat服务的完全版本。启动服务后,测试URL:http://localhost:8080/expresso/frame.jsp

3.2 配置expresso-config.xml

Expresso的主要配置信息文件,它在服务启动时被ConfigManager对象读入,应用里的任何对象均可通过ConfigManager对象对之进行操作。ConfigManager是一个单一实例模式的对象,甚至在配置了几个数据上下文(连接池)项目。信息包括:将日志写在哪个目录;"class-handlers"部分指明Expresso和应用使用的变量和所实现的类的对应关系,即相对于程序设计里的变量申明;"context"部分通常是数据库的配置。一旦expresso-config.xml被读入,安装信息便从每个对应数据库中读入,每个连接池也就初始化好了。数据库的使用通常是:保持使用“Default”为Expresso自带的数据库,另外增加一数据库上下文配置为用户提供数据存放,通过登陆时切换数据库。在配置文件里使用<hasSetupTables>false</hasSetupTables>进行区分。
登陆切换数据库Html语句如下:<input type="HIDDEN" name="dbContext" value="default" >

3.3 国际/本地化问题

本地化(中文)问题与MessagesBundle_*.properties文件有关,可用修改MessagesBundle_zh.properties文件使Expresso的界面中文化。可以使用native2ascii命令完成编码转换。项目界面的中文化问题建议采用重新编写自己项目View部分的jsp,并通过编写继承的Controller或重定义Action实现。这样,就避免破坏原Expresso结构。也就是说,借用Expresso功能时,我们不借用“界面”部分,当然,该部分对界面的开发有着很高的借鉴意义。

4 Expresso功能列表

1. 提供应用的组织和配置;2. 提供数据库访问和数据对象工具包;3. 支持MVC结构和创建几种类型的Controller对象的组件包;4. 提供任务队列操作;5. 提供容易快速创建Servlet和JSP的方法;6. 提供定义那些发生在Web应用之间的事件机制;7. 提供一定数量的其他有用的功能;
8. 日志功能;9. 用户安全功能;10. 初始化机制;11. 数据库数据缓冲管理;

5 最佳实践

一个典型的Web应用通常是由一组数据(Database)对象(包括Model和持久化数据库),控制(Controller)对象、工作任务(Job)对象和一个单一的计划(Schema)对象将它们紧紧地联系在一起。在这种情况下,应用可以使用一个普通的“View handler”进行测试。以下的提供的源码是一个股票买卖的例子,Orange Trader,2002年4月由Peter Pilgrim编写。

5.1 创建包

通常需要创建如下包:² dbobj: 包含数据库对象;² controller: 包含控制器对象;² job: 包含工作任务对象,可选;

5.2 创建一个Schema对象

Schema:a Web Application Context object创建一个Schema对象,放在包的根;Schemo对象为Expresso提供全部的引用,用以安全管理等(注册后),这是设计模式的FACADE模式思想。
必需做的工作:1. 加入所有的和应用相关的controllers, dbobjects or jobs;2. 设置MessageBundle路径,getMessageBundlePath()返回国际化项目资源所在路径;
最容易的方法是拷贝一个现成的Schema类进行修改,如:<OrangeTraderSchema.java>import com.jcorporate.expresso.core.db.*;import com.jcorporate.expresso.core.dbobj.Schema;public class OrangeTraderSchema extends Schema{ public OrangeTraderSchema() throws DBException { super(); try { addDBObject( "com.xenonsoft.orangetrader.ot1.dbobj.StockTrade" ); addController( "com.xenonsoft.orangetrader.ot1.controller.StockController" ); } catch ( Throwable t ) { throw new DBException( t.getMessage() ); } }
public String getMessageBundlePath() { return "com/xenonsoft/orangetrader"; }}

5.3 创建一些需要的数据(DB)对象

通常情况下,所有数据对象类均放在dbobj包里,并使用Schema类注册这些数据对象,以便DBTool和DBCreate能够使用它们。数据对象是为Expresso的持久层而设计的,相当于EJB里的Entity JavaBean(若使用EJB,可对应移植),是表在关系数据库里的直接映射。使用数据对象的优势在于:缓冲机制、值校验、引用完整性和数据安全;可以避免编写SQL语句,而这些SQL语句由于不同的数据库系统有不同的版本;数据对象和业务逻辑是相关的,通过引用完整性和复杂的表间关系可以达到和存储过程一样的效果。这样就实现了“与数据库无关”。创建的方法有很多,一个DBObject里必需的实现constructors、setupFields、getThisDBObj()方法。
< StockTrade.java >import com.jcorporate.expresso.core.dbobj.*;import com.jcorporate.expresso.core.db.*;
public class StockTrade extends SecuredDBObject{public StockTrade() throws DBException { super(); }
public StockTrade(DBConnection theConnection) throws DBException { super(theConnection); }
protected synchronized void setupFields() throws DBException{ setTargetTable("STOCKTRADE"); setDescription("Stock Trade I"); addField("ST_ID", "int", 0, false, "Text Channel Autoincrement ID"); addField("ST_TITLE", "varchar", 40, false, "Stock Title"); addField("ST_TRADER", "varchar", 40, false, "Owner Trader"); addField("ST_STATUS", "varchar", 10, true, "Trade Status" ); addField("ST_PRICE", "float", 0, true, "Current Price" ); addField("ST_ASK", "float", 0, true, "Asking Price" ); addField("ST_BID", "float", 0, true, "Bid Price" ); addField("ST_CHANGE", "float", 0, true, "Percentage Change" );
addKey("ST_ID");}
public DBObject getThisDBObj() throws DBException { return new StockTrade(); }}

5.4 创建一些需要的控制器(Controller)对象

一个控制器就是应用从当前状态转换成下一状态的访问点。这就是Finite State Machine的思想。最典型的例子就是ATM自动取款机,和你交互的取款机就是一个控制器,每一次交互就对应控制器的一个功能单元(State)。控制器对象类通常放在Controller包里。控制器对象封装了应用的大部分业务逻辑(数据对象也有业务逻辑),象征着整个应用的业务层。你可以单独地去设计你的表示层,充分考虑输入和输出。控制器中有着“run+状态名(首字母大写)+State”的方法会在调用相应状态名时被自动调用,该方法还应该申明为void和private或protected。
Controller和View的接口:Controller的输入:命令行参数;From_bean方式Controller的输出:通常采用Block对象集合传递参数,Block又可包含Input、Output、Action对象。
< StockController.java >import java.util.*import com.jcorporate.expresso.core.controller.*;import com.jcorporate.expresso.core.controller.session.*;import com.jcorporate.expresso.core.dbobj.*;import com.jcorporate.expresso.core.db.*;import com.xenonsoft.orangetrader.ot1.dbobj.StockTrade;
public class StockController extends DBController{public StockController(){ super();

addState( new State("displayStocks", "displayStocks")); addState( new State("promptBuyStock", "Prompt Buy Stock")); addState( new State("promptSellStock", "Prompt Sell Stock")); addState( new State("buyStock", "Buy Stock")); addState( new State("sellStock", "Sell Stock")); setInitialState("displayStocks"); //一定别忘了
}
public String getTitle() {return "Stock Controller II";}
protected ControllerResponse runDisplayStocksState( ControllerRequest myRequest, ControllerResponse myResponse ) throws ControllerException{ String myName=thisClass+"displayStocks() "; System.out.println( myName );
try { // Create a block called "StockList" which is the root of the controller // response. Block blockList = new Block("StockList" );
// We retrieve all the stocks from the database. For each row // tuple form the database we create an Output for it. StockTrade stockInit = new StockTrade(); stockInit.setDBName( myRequest.getDBName() ); ArrayList list = stockInit.searchAndRetrieveList( "ST_TITLE" ); int N=list.size(); for ( int k=0; k<N; ++k ) { StockTrade stock = (StockTrade)list.get(k); // Create a Block for each row tuple Block blockRow = new Block("Stock"+k ); blockList.add( blockRow ); // Create an Output for the DBObject row tuple and add to // the row Block Output out1 = new Output(); out1.setName( "Detail" ); out1.setAttribute( "Title", stock.getField("ST_TITLE") ); out1.setAttribute( "Trader", stock.getField("ST_TRADER") ); out1.setAttribute( "Price", stock.getField("ST_PRICE") ); out1.setAttribute( "Ask", stock.getField("ST_ASK") ); out1.setAttribute( "Bid", stock.getField("ST_BID") ); out1.setAttribute( "Change", stock.getField("ST_CHANGE") ); out1.setAttribute( "Status", stock.getField("ST_STATUS") ); blockRow.add( out1 ); // out1.setAttribute( "", stock.getField("ST_") );
// Add a "buy" transition // NOTE: this state requires a request parameter "buyPage" // to specifies the JSP of the prompt buy view Transition buyTransition = new Transition("Buy", getClass().getName() ); buyTransition.setName( "Buy" ); buyTransition.addParam("state", "promptBuyStock"); buyTransition.addParam("stock", stock.getField("ST_ID") ); blockRow.add(buyTransition); // Add a "sell" transition // NOTE: this state requires a request parameter "sellURL" // to specifies the JSP of the prompt sell view Transition sellTransition = new Transition("Sell", getClass().getName() ); sellTransition.setName( "Sell" ); sellTransition.addParam("state", "promptSellStock"); sellTransition.addParam("stock", stock.getField("ST_ID") ); blockRow.add(sellTransition); } // Finally add the block to the list myResponse.addBlock( blockList ); } catch (DBException dbe) { throw new ControllerException( myName+ " database exception: "+dbe.getMessage() ); }
myResponse.setStyle("displayStocks" ); return myResponse;}//……More code}
构造器里不能少的是调用父类方法super()和setInitialState();而super.newState(newState)则是应用安全规则所必需的。
以下为显示页面< orangetrader/ot2 /index.jsp><%@ page language="java" contentType="text/html; charset=ISO-8859-1" %><%@ taglib uri="/xenon" prefix="xenon" %><%@ taglib uri="/xspresso" prefix="xspresso" %>
<%@ page import="com.xenonsoft.orangetrader.ot1.dbobj.StockTrade" %><%@ page import="com.xenonsoft.orangetrader.ot1.controller.StockController" %>
<table width="100%" border="1" cellspacing="1" cellpadding="2" > <tr> <th> <b>Title</b> </th> <th> <b>Trader</b> </th> <th> <b>Price</b> </th> <th> <b>Ask</b> </th> <th> <b>Bid</b> </th> <th> <b>Change</b> </th> <th> <b>Status</b> </th> <th colspan="2"> <b>Command</b> </th> </tr>
<xspresso:block blockPath="StockList" id="blockStocks" >
<xenon:loop name="blockStocks" property="nested" loopId="block" className="com.jcorporate.expresso.core.controller.Block" counterId="counter" >
<tr bgcolor="<%= ( counter.intValue() % 2 == 0 ? "#F0F0F0" : "#E0E0E0" ) %>" > <xspresso:output outputPath="Detail" blockName="block" > <td> <xspresso:outputAttribute property="Title" />   </td> <td> <xspresso:outputAttribute property="Trader" />   </td> <td> <xspresso:outputAttribute property="Price" />   </td> <td> <xspresso:outputAttribute property="Ask" />   </td> <td> <xspresso:outputAttribute property="Bid" />   </td> <td> <xspresso:outputAttribute property="Change" />   </td> <td> <xspresso:outputAttribute property="Status" />   </td> </xspresso:output>
<form action="<%= contextPath %>/StockController2.do?cmd=button" method="POST" > <td> <xspresso:transition transitionName="Buy" blockName="block" htmlClass="orange-form-submit-orange" /> </td> <td> <xspresso:transition transitionName="Sell" blockName="block" htmlClass="orange-form-submit-orange" /> </td> </form> </tr> </xenon:loop></xspresso:block></table>

5.5 创建一些需要的工作任务(Job)对象

Job对象通常被用在那些不需要用户交互而独立运行的任务,或者是把一耗时长的任务封装到一个线程里处理。Job对象和用户间通常采用消息通讯。Job对象通常放在job包里。每一Job对象均对应一个JobHandler线程,JobHandler线程能被配置成在连接数据库后自动执行。(本例不涉及Job对象)

5.6 安装Expresso应用

5.6.1 在config目录里创建XML配置文件

struts-config.xml该文件是Expresso框架在Struts组件里自身的URL's到"Action"对象的映射关系,一般情况下,用户不必调整此文件。用户的Struts对应关系由用户编写XXX-config.xml完成(XXX表示应用的名字),具有这样命名格式的配置文件在struts-config.xml被读取时一同被读取,编写方法可借鉴struts-config.xml,更多内容请阅读Struts文档。以下为orange-struts-config.xml文件部分内容: <action path="/StockController2" type="com.xenonsoft.orangetrader.ot2.controller.StockController" scope="request" validate="false"> <forward name="displayStocks" path="/orangetrader/ot2/index.jsp" /> <forward name="promptBuy" path="/orangetrader/ot2/buy.jsp" /> <forward name="promptSell" path="/orangetrader/ot2/sell.jsp" /> </action>其实质表示:1. 动作的输入为/StockController2.do?state= displayStocks;2. 在执行/orangetrader/ot2/index.jsp之前插入了StockController的一段代码,相当于传统的Jsp头部的嵌入式脚本;3. StockController和Jsp之间的数据采用Block对象传递;4. 在页面中的服务器脚本交由标签处理。
expressoLogging.xml定义Expresso使用Log4j各对象产生日志的等级,用户应用使用Log4j各对象产生的日志等级由XXX Logging.xml定义,XXX表示应用的名字。expressoLogging.xml文件由LogManager进行读入管理,ConfigManager是第一个调用LogManager的对象。

5.6.2 注册Schema和创建/初始化数据库

启动Expresso的Tomcat服务程序,使用浏览器打开Expresso主页:http://localhost:8080/expresso/frame.jsp,使用Admin登陆,选择“Applications”页,使用Component Manager去添加注册Schema。上例如下设置: Schema Class File: com.xenonsoft.orangetrader.OrangeTraderSchema Schema Description: OrangeTrader DemoComponent Code: orangetrader
在Setup也,使用Create/Verify Database Structure & Perform Initial Setup来创建数据库表。
使用浏览器输入URL:http://localhost:8080/应用目录/ 就可以开始你的应用了。

6 Expresso专题

6.1 数据对象

继承自SecuredDBObject类的数据对象无需加入任何代码便有了安全属性,也就是说,可以用此来控制某个用户是否可用该数据对象。
在SetupFields里可以使用:使用setDBName(String)方法可以指定数据库;
addDetail方法可以实现表间Master/Detail关系,并应用主从表规则如自动删除、键置更新等;
还可以通过setLookupObject方法实现一个数据对象对应多个表的情况。
通过Schema注册数据对象的不同方法,可以将表映射到不同机器的数据库中。

6.2 控制器对象

Controller和DBController的不同就象DBObject之于SecuredDBObject,均是安全性的不同。一个控制器可类似地对应一个use case,每个State便是use case的细节用例。控制器能被各种各样的客户端程序调用: Servlet,JSP,Applet和Application。控制器是居留内存的,不安全线程代码是一个可怕恶梦,请注意使用synchronized(针对静态数据成员)或Hashtable来处理线程安全性问题。
控制器活动图:
状态:椭圆表示;
输出:带名字的箭头表示;
每个控制器状态都是安全线程模式的,也就是说:不可能指望在状态间共享内存变量。你可用通过在expresso-config.xml插入如下行而修改成自己的登陆界面(而不是通过修改Expresso自带的Jsp文件):<class-handler name="login" classHandler="com.jcorporate.myproject.controller.MyLoginController"/>

6.3 初始化Expresso为Java Application环境

让Expresso不是Web Application方式执行也是可能的,如下就是一个例子:com.jcorporate.expresso.core.utility.JobHandler,这时Struts将不能使用,但是ConfigManager、CacheManager、DB connection pools和logging等仍能使用。

6.4 DBTool和DBCreate

DBTool是一个脱离Web环境的Java Application,DBCreate/DBTool可以通过用户定义的DBObject在数据库里创建表,也可以反过来,从数据表产生Java bean(DBObject)。

6.5 数据库连接池

支持多连接池,可同时提供多个分布在不同机器、不同类型的数据库连接池,也就是说,可以实现例如将Sybase的数据导入Oracle数据库的功能。

7 使用Expresso框架后工作划分

7.1 分析和设计人员(包括数据库设计)

² 系统分析² 需求分析² 软件设计1. 控制器和视图之间的数据交换接口2. MVC设计图3. 由控制器延伸业务相关类图4. 由控制器延伸业务相关序列图5. 数据字典6. 表间关系、触发器和存储过程
7. 不再需要Web Application的结构设计

7.2 美工、界面设计人员

² 熟悉标签库² 输入界面² 输出界面

7.3 程序员

² 编写控制器对象² 延伸出来的业务相关Java Bean² 数据对象(按照数据库设计人员的数据字典编写表的创建脚本代码)

8 Expresso和Spring+Hiberate组合结构的比较

1. Expresso最大的亮点就是引入了作为业界MVC标准的Struts,并以之为核心思想,实现了一个表示层-业务层-持久层的应用框架。2. Expresso没有使用第三方持久层组件,持久层和连接池为自主开发,效率值得考证。事实上,持久层的强大功能也是Expresso的一大亮点,她将“与数据库无关”理论实现得相当完美。3. Expresso整个系统所引入的东西较多(多于200个文件),包括很多JSP、Java Bean、配置XML、数据库表等,造成本身的结构都很复杂,给学习者带来较大的困难,且怎么取舍那么多界面元素的.jsp还是个问题。4. Expresso本身就是一个Web应用,不象许多第三方组件商,仅提供.jar包,因此使用该框架进行开发,就使用方法方面带来了差异。与其说是使用Expresso工具为我们的项目应用服务,还不如说是扩展开发Expresso。Expresso带来的是一些现成的工具,同时带来了一种开发模式。开发模式和开发方式比较固定,自由度较低,层级功能是很难单个拆分的,如去掉Expresso的用户安全系统可能就比较难了。5. Spring等其他框架,使用时更象是使用一种第三方工具,使用过程通过实例创建和方法调用完成。由于使用时就只引入几个有限的Jar文件,感觉起来封装性较好,使用时更自由,当然也就没有安全模块这样的公共模块了。6. Spring、iBatis等其他第三方组件,通常直接采用HashMap对象传递数据,Expresso里则采用Block对象。

9 开发Expresso建议

为保持Expresso的完整性,请遵守不要修改系统所带来的*.jsp、*.java文件,配置文件xml内容尽量只增加不修改的原则。项目的目录结构视Expresso为一个组件,尽量不要将项目的目录放入Expresso目录结构中,以免查找困难。project | +-- src - 源文件 | +-- lib – 包文件 | +-- docs – 文档 | +-- build -编译后的发布结构 | +-- web--expresso - Expresso的jsps | +---WEB-INF - 发布的lib、Classes,包含Expresso的 | +---project jsps - 项目的jsp,按模块分

10 参考资料

Expresso Developer's GuideBest Practice with Expresso Framework: Using a framework to create a web applicationDBMaint A Step-by-Step Example
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息