2.1 纵览 |
很多用于构造web程序的需求文档都是关注于View(视图)的。但是,你需要确认每一个确定的请求需要的处理也是在Model(模型)层清楚的定义的。一般说来,Model(模型)的开发者会关注如何建立满足所有功能需求的JavaBean类。一个特定的程序所需要的明确定义的bean会有很大不同,取决于他们的需求。然而他们大致上可以被归为下面会讨论的几类。然而,先做一个关于“Scope范围”这个概念的简要的回顾会是很有用的。
|
2.2 JavaBeans 和 scope(范围) |
在一个基于web的程序中,JavaBean可以被存放在(也是获取于)几个不同的“属性”集合。每一个集合有不同的关于集合的生存期和储存在其中的bean的可视范围的规则。定义生存期和可视范围的规则共同被称为这些bean的“scope(范围)”。JavaServer pages(JSP)的规格书定义了以下的术语(在servlet API中同样的也有这些定义):
- page - Bean在一个单一的JSP页面中可见,生存期是这个请求。(
service() 函数的本地变量)
- request - Beans 在一个单一的JSP页面中可见,包括被包含在这个页面中或者被此页面转移到的任何页面或者servlet. (Request 属性)
- session - Beans 在一个特定的用户session中的所有JSP页面和Servlet中可见,跨越一个或多个请求。(Session 属性)
- application - Beans 在web 程序的所有的JSP页面和servlet中可见。 (Servlet context属性)
记住同一个web程序中的JSP页面和servlet共享同样的bean集合是很重要的。例如,如下的代码在一个servlet中把一个bean加入了request的属性:
MyCart mycart = new MyCart(...); request.setAttribute("cart", mycart);
马上在这个servlet转移到的JSP页面中可见,通过使用一个标准的动作tag,就像这样:
<jsp:useBean id="cart" scope="request" class="com.mycompany.MyApp.MyCart"/>
|
2.3 ActionForm Beans |
注意:ActionForm Beans实际上更靠近View(视图)而非Model(模型)。
Struts框架一般会假设你已经为你程序中每一个需要输入的Form定义好了一个ActionForm Bean(这是一个从ActionForm 继承的一个类).ActionForm beans有时候就叫做"form beans"。如果你已经在你的ActionMapping 配置文件里(参阅"构造Controller(控制器)部件")生命了这些bean, Struts Controller servlet在调用合适的Action 方法之前会自动为你提供如下服务:
- 在用户的session里面察看在恰当的键值下是否有一个合适的类的实例。
- 如果没有这样的session范围的bean存在,会自动创建一个新的实例并加入到user的session中。
- 对每一个request 参数,如果能对应于(form) bean的一个同名属性,会调用相应的setter方法。这个操作很象标准的JSP动作
<jsp:setProperty> ,当你用'*'符号来选择所有的属性的时候。
- 更新过的
ActionForm bean 会被传递到Action 类的perform() 方法,(当这个方法被调用时)这些值马上就可以使用了。
当你编写你的 ActionForm bean的时候,记住这些基本的原则:
ActionForm 类本身不需要实现具体的方法。它是用来为了明确特殊的bean在整个体系中的角色的。一般来说,一个ActionForm bean 只需要属性的getter和属性的setter方法,没有商业逻辑。
- ActionForm 对象也提供了一个标准的检查机制。如果你重载了一个"stud"函数,并且在标准的程序资源里给出了错误信息,Struts会自动检查输入的值(使用你的方法)。参阅"Action Form 检查" 得到详细说明。当然,你可以忽略在ActionForm中的检查而在你的Action对象中自己进行。
- 为每一个form中出现的字段定义一个属性(附带相应的
getXxx() 和setXxx() 方法)。字段的命名和属性的命名必须遵循通常的JavaBeans规范。举例来说,一个输入的字段名叫username 会导致setUsername() 方法被调用。
- 设想你的ActionForm bean是HTTP和Action之间的防火墙。用validate方法来保证所有需要的书形式存在的,并且包含合理的值。一个没有通过检查的ActionForm不会被送到Action去处理。
- 你也可以在你的form里面放置一个bean的实例,来使用内置的属性引用。比如,你可能在你的ActionForm上有一个“customer”bean,可以在你的JSP 中使用属性"customer.name"。这会对应到你的customer bean的
customer.getName() 和customer.setName() 方法。 参阅 tag Library Develiper Guides 得到更多关于内置属性语法的说明。
- 警告: 如果你在你的form上放置一个以存在的bean的实例,考虑它暴露出来的属性。任何public的,接受一个单一的字符串的属性可能被一个查询字符串重置。这些bean放在一个瘦的“包装者”类里面,只暴露需要的属性可能时有所帮助的。这个包装者也可以提供一次过滤来保证运行时的属性不被置为无意义的值。
你可能注意到了一个在这里讨论的"form",并非必须是用户界面端一个单独的JSP页面。在很多程序里都会出现跨越多个页面的"form"(从使用者的角度来说)。想一下,举例来说,在安装新程序时经常会出现的向导风格的用户界面。Struts鼓励你定义一个单独的ActionForm 包含所有可能用到的属性,不管到底是在那个页面显示的。同样的,同一个form的不同页面应该被提交到同样的Action类。如果你遵循这些建议,页面设计者可以重新在页面之间安排这些字段,通常不需要修改处理逻辑。
|
2.4 系统状态Beans |
系统的实际状态一般会表现为一套包括一个或多个JavaBean类,它们的属性定义了当前的状态。一个购物车,举例来说,会包括为每一个购物者维护一个bean,并且会(和其他属性一起)包括一些购物者当前选择的物品条目。另外,系统也会包括不同的bean来保存用户的个人资料(包括他们的信用卡号码和送货地址),还有按照他们的购物等级所能得到的可购买物品清单。
对于一个小型的系统,或者对不需要长期保存状态信息的系统来说,一套系统状态bean可能已经保存了系统所需要的全部特定细节。否则,大多数情况下,系统状态bean会把它持有的信息包村到一个外部的数据库去(比如一个CustomerBean 对象对应于CUSTOMERS表中的一个特定的行),并可以在服务器的内存中按照需要创建或者删除。Entity Enterprise JavaBeans 在大规模系统也是为了这个目的使用的。
|
2.5 商业逻辑 Beans |
你应该把你的程序的功能逻辑封装在你为此设计的JavaBean的方法调用中。这些方法可能是同一个系统状态bean,或者他们分布在不同的类中,潜在的体现了逻辑。在后一种状况中,你往往需要把系统状态bean作为参数调用以便这些方法处理。
为了最大化代码重用,商业逻辑bean因为被设计和实现为假设它们不知道会在web环境下被执行。如果你发现你在你的bean中importjavax.servlet.* ,你(就知道你在)在试图把这个商业逻辑bean放置在web环境中。请考虑重新编排,让你的Action 类(属于controller角色的一部分,下文将会谈到)从HTTP请求翻译所有需要的信息,通过调用你的商业逻辑bean的setter方法预置,然后调用一个execute() 方法来执行。这样的商业逻辑类可以在不是最初的Web的环境下重用。
取决于你的程序的复杂程度和范围(宽广程度),商业逻辑bean可能是普通的JavaBeans(它们和作为参数传递的系统状态bean打交道),或者是通过JDBC调用存取数据库的一般的JavaBeans。对于大规模程序来说,它们往往是被有状态的或者无状态的Enterprise JavaBeans(EJBs)所取代。
|
2.6 访问关系数据库 |
Struts可以在它的标准配置文件中为程序定义datasource.也提供一个简单的JDBC连接池。参阅Action Mappings 配置文件和Utilities Developer Guide(工具开发指南)得到更详细的信息。
当datasource被定义号之后,下面是一个在Action的perform方法中取得连接的例子。 public ActionForward
perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
{
try {
javax.sql.DataSource dataSource =
servlet.findDataSource(null);
java.sql.Connection myConnection =
dataSource.getConnection();
//do what you wish with myConnection
} catch (SQLException sqle) {
getServlet().log("Connection.process", sqle);
} finally {
//enclose this in a finally block to make
//sure the connection is closed
try {
myConnection.close();
} catch (SQLException e) {
getServlet().log("Connection.close", e);
}
}
}
注意Struts 普通连接池是一个可选组件。很多Struts程序使用其它连接池来获取更高的性能,特别是大流量的生产系统。
|
posted on 2005-08-13 02:18
R.Zeus 阅读(219)
评论(0) 编辑 收藏 所属分类:
STRUTS