Expresso使用说明

Expresso是一个基于Struts的Java开源项目,旨在规范化开发结构,提供数据库访问和数据对象工具。本文介绍了Expresso的安装配置、功能列表、最佳实践、数据库连接池以及与Spring+Hibernate框架的比较。通过创建Schema对象、数据(DB)对象、控制器(Controller)对象,开发者可以快速搭建Web应用。同时,文章强调了使用Expresso框架后的工作划分,包括分析设计、界面设计和程序员的工作内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Expresso使用说明

 

 

修订历史记录

日期

版本

说明

作者

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             初始化ExpressoJava Application环境    12

6.4             DBToolDBCreate. 12

6.5             数据库连接池    12

7     使用Expresso框架后工作划分... 12

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

7.2             美工、界面设计人员    12

7.3             程序员    12

8     ExpressoSpring+Hiberate组合结构的比较    13

9     开发Expresso建议... 13

10          参考资料    14

 


1         简介

Expressojcorporate提供的一Java开源项目,项目组主要的收入来源是出售该项目的服务支持(目前每年的服务支持费是$999.00US)。

Expresso基于Struts,也就是说Struts是它的核心思想。

Expresso的安装包里,expresso/doc提供了完整的文档。最新版本的软件包可以从如下网址获得:

http://www.jcorporate.com

 

 

2         引入框架开发的目的

总结起来,目的大概如下三条:

1.      规范化开发结构;

2.      提供大多数项目均需要的服务功能,如日志、持久层管理等;

3.      提供开发工具和方法,以加快开发速度。

没有结构不成方圆,程序设计从最初的机器语言发展为结构化的高级语言,从面向过程发展为面向对象,其内在原因就是由于开发的规模在急剧扩大。我们可以采用各种方法实现我们的软件项目,可是没有组织好的上千万行代码将带来的结果是可读性极低、可扩展性极差。“项目的开发象一头巨兽陷在泥潭,越陷越深。”

软件需求变幻无穷,计划没有变化快,但是我们还是要寻找出不变的东西,并将它和变化的东西分离开来,框架就是这一思想的成果。

 

3         安装与配置

3.1       有两种安装方法

解压下载来的expresso5.0.5.zipexpresso5-0-5-src.zipexpresso5.0.5.war均能得到一个Expresso的应用,也就是开发环境;

解压下载来的expresso5-0-5-complete.zip将得到一个带有Tomcat服务的完全版本。

启动服务后,测试URLhttp://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.      提供容易快速创建ServletJSP的方法;

6.      提供定义那些发生在Web应用之间的事件机制;

7.      提供一定数量的其他有用的功能;

 

8.      日志功能;

9.      用户安全功能;

10.  初始化机制;

11.  数据库数据缓冲管理;

 

5         最佳实践

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

 

5.1       创建包

通常需要创建如下包:

²       dbobj: 包含数据库对象;

²       controller: 包含控制器对象;

²       job: 包含工作任务对象,可选;

 

5.2       创建一个Schema对象

Schemaa 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类注册这些数据对象,以便DBToolDBCreate能够使用它们。

数据对象是为Expresso的持久层而设计的,相当于EJB里的Entity JavaBean(若使用EJB,可对应移植),是表在关系数据库里的直接映射。使用数据对象的优势在于:缓冲机制、值校验、引用完整性和数据安全;可以避免编写SQL语句,而这些SQL语句由于不同的数据库系统有不同的版本;数据对象和业务逻辑是相关的,通过引用完整性和复杂的表间关系可以达到和存储过程一样的效果。这样就实现了“与数据库无关”。

创建的方法有很多,一个DBObject里必需的实现constructorssetupFieldsgetThisDBObj()方法。

 

< 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”的方法会在调用相应状态名时被自动调用,该方法还应该申明为voidprivateprotected

 

ControllerView的接口:

Controller的输入:

命令行参数;From_bean方式

Controller的输出:

通常采用Block对象集合传递参数,Block又可包含InputOutputAction对象。

 

< 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" /> &nbsp; </td>

    <td> <xspresso:outputAttribute property="Trader" /> &nbsp; </td>

    <td> <xspresso:outputAttribute property="Price" /> &nbsp; </td>

    <td> <xspresso:outputAttribute property="Ask" /> &nbsp; </td>

    <td> <xspresso:outputAttribute property="Bid" /> &nbsp; </td>

    <td> <xspresso:outputAttribute property="Change" /> &nbsp; </td>

    <td> <xspresso:outputAttribute property="Status" /> &nbsp; </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.      StockControllerJsp之间的数据采用Block对象传递;

4.      在页面中的服务器脚本交由标签处理。

 

expressoLogging.xml

定义Expresso使用Log4j各对象产生日志的等级,用户应用使用Log4j各对象产生的日志等级由XXX Logging.xml定义,XXX表示应用的名字。

expressoLogging.xml文件由LogManager进行读入管理,ConfigManager是第一个调用LogManager的对象。

 

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

启动ExpressoTomcat服务程序,使用浏览器打开Expresso主页:http://localhost:8080/expresso/frame.jsp,使用Admin登陆,选择“Applications”页,使用Component Manager去添加注册Schema

上例如下设置:

    Schema Class File:       com.xenonsoft.orangetrader.OrangeTraderSchema

    Schema Description:       OrangeTrader Demo

Component Code:       orangetrader

 

Setup也,使用Create/Verify Database Structure & Perform Initial Setup来创建数据库表。

 

使用浏览器输入URLhttp://localhost:8080/应用目录/ 就可以开始你的应用了。

 

6         Expresso专题

6.1       数据对象

继承自SecuredDBObject类的数据对象无需加入任何代码便有了安全属性,也就是说,可以用此来控制某个用户是否可用该数据对象。

 

SetupFields里可以使用:

使用setDBName(String)方法可以指定数据库;

addDetail方法可以实现表间Master/Detail关系,并应用主从表规则如自动删除、键置更新等;

还可以通过setLookupObject方法实现一个数据对象对应多个表的情况。

 

通过Schema注册数据对象的不同方法,可以将表映射到不同机器的数据库中。

 

6.2       控制器对象

ControllerDBController的不同就象DBObject之于SecuredDBObject,均是安全性的不同。一个控制器可类似地对应一个use case,每个State便是use case的细节用例。

控制器能被各种各样的客户端程序调用: ServletJSPAppletApplication

控制器是居留内存的,不安全线程代码是一个可怕恶梦,请注意使用synchronized(针对静态数据成员)或Hashtable来处理线程安全性问题。

控制器活动图:

状态:椭圆表示;

输出:带名字的箭头表示;

每个控制器状态都是安全线程模式的,也就是说:不可能指望在状态间共享内存变量。

你可用通过在expresso-config.xml插入如下行而修改成自己的登陆界面(而不是通过修改Expresso自带的Jsp文件):

<class-handler name="login"

classHandler="com.jcorporate.myproject.controller.MyLoginController"/>

 

 

6.3       初始化ExpressoJava Application环境

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

 

6.4       DBToolDBCreate

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

 

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         ExpressoSpring+Hiberate组合结构的比较

1.      Expresso最大的亮点就是引入了作为业界MVC标准的Struts,并以之为核心思想,实现了一个表示层-业务层-持久层的应用框架。

2.      Expresso没有使用第三方持久层组件,持久层和连接池为自主开发,效率值得考证。事实上,持久层的强大功能也是Expresso的一大亮点,她将“与数据库无关”理论实现得相当完美。

3.      Expresso整个系统所引入的东西较多(多于200个文件),包括很多JSPJava Bean、配置XML、数据库表等,造成本身的结构都很复杂,给学习者带来较大的困难,且怎么取舍那么多界面元素的.jsp还是个问题。

4.      Expresso本身就是一个Web应用,不象许多第三方组件商,仅提供.jar包,因此使用该框架进行开发,就使用方法方面带来了差异。与其说是使用Expresso工具为我们的项目应用服务,还不如说是扩展开发ExpressoExpresso带来的是一些现成的工具,同时带来了一种开发模式。开发模式和开发方式比较固定,自由度较低,层级功能是很难单个拆分的,如去掉Expresso的用户安全系统可能就比较难了。

5.      Spring等其他框架,使用时更象是使用一种第三方工具,使用过程通过实例创建和方法调用完成。由于使用时就只引入几个有限的Jar文件,感觉起来封装性较好,使用时更自由,当然也就没有安全模块这样的公共模块了。

6.      SpringiBatis等其他第三方组件,通常直接采用HashMap对象传递数据,Expresso里则采用Block对象。

 

 

9         开发Expresso建议

为保持Expresso的完整性,请遵守不要修改系统所带来的*.jsp*.java文件,配置文件xml内容尽量只增加不修改的原则。

项目的目录结构视Expresso为一个组件,尽量不要将项目的目录放入Expresso目录结构中,以免查找困难。

project

   |

   +-- src - 源文件

   |

   +-- lib – 包文件

   |

   +-- docs – 文档

   |

   +-- build -编译后的发布结构

   |

   +-- web--expresso - Expressojsps

        |

        +---WEB-INF  - 发布的libClasses,包含Expresso

        |

        +---project jsps - 项目的jsp,按模块分

 

10    参考资料

Expresso Developer's Guide

Best Practice with Expresso Framework: Using a framework to create a web application

DBMaint A Step-by-Step Example

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值