Struts1.1介绍
前一段时间好象有人问关于Struts的事情,本人留意了一下.请有兴趣的同志不防研究研究.
(1)
1. 介绍
1.1 Model-View-Controller (MVC) 设计模式
FIXME - 需要一个对该模式一般性的介绍。(译注:可以参考机械工业出版社的《设计模式》。)
1.2 将MVC概念映射到Struts组件中
Struts 的体系结构实现了Model-View-Controller设计模式的概念,它将这些概念映射到web应用程序的组件和概念中。
这一体系结构中每个主要的组件都将在下面做详细的讨论。
1.3 Model: 系统状态和商业逻辑JavaBeans
基于MVC的系统中的 Model 部分可以细分为两个概念 -- 系统的内部状态, 能够改变状态的行为。用语法术语来说,我们可以把状态信息当作名词(事物),把行为当作动词(事物状态的改变)。
通常说来,你的应用程序将系统内部的状态表示为一组一个或多个的JavaBeans,使用属性(properties)来表示状态的细节。依赖于你的应用程序的复杂度,这些beans可以是自包含的(以某种方式知道怎样永久地保存它们的状态信息),或者可以是正面的(facades),知道当被请求时怎样从外部数据源(例如数据库)中取得信息。Entity EJBs通常也用来表示内部状态。
大型应用程序经常将系统可能的商业逻辑行为表示为可以被维护状态信息的beans调用的方法。举个例子,你有一个为每个当前用户保存在session中的购物车bean,里面是表示当前用户决定购买物品的属性。这个bean有一个checkOut()方法用来验证用户的信用卡,将定单发给库房以选择货品和出货。别的系统分别地表示同样的行为,或许使用Session EJBs。
在一些小型应用程序中,同样的行为又可能嵌入到作为Controller一部分的 Action 类中。这在逻辑非常简单或者并不想要在其它环境中重用这些商业逻辑时是恰当的。Struts框架支持所有这些方法,但建议将商业逻辑(“做什么”)和 Action 类(“决定做什么”)分离开。
1.4 View: JSP页面和表示组件
基于Struts的应用程序中的 View 部分通常使用JSP技术来构建。JSP页面包含称为“模版文本”的静态HTML(或XML)文本,加上插入的基于对特殊行为标记解释的动态内容。JSP环境包括了其用途由JSP规范来描述的一套标准的行为标记,例如 <jsp:useBean> 。另外,还有一个用来定义你自己标记的标准机制,这些自定义的标记组织在“定制标记库”中。
Struts包括了一个广阔的便于创建用户界面,并且充分国际化的定制标记库,与作为系统 Model 部分一部分的ActionForm beans美妙地相互配合。这些标记的使用将在后面做详细讨论。
除了JSP页面和其包含的行为及定制标记,商业对象经常需要能够基于它们在被请求时的当前状态将自己处理成HTML(或XML)。从这些对象处理过的输出可以很容易地使用 <jsp:include> 标准行为标记包括在结果的JSP页面中。
1.5 Controller: ActionServlet和ActionMapping
应用程序的 Controller 部分集中于从客户端接收请求(典型情况下是一个运行浏览器的用户),决定执行什么商业逻辑功能,然后将产生下一步用户界面的责任委派给一个适当的View组件。在Struts中,controller的基本组件是一个 ActionServlet 类的servlet。这个servlet通过定义一组映射(由Java接口 ActionMapping 描述)来配置。每个映射定义一个与所请求的URI相匹配的路径和一个 Action 类(一个实现 Action 接口的类)完整的类名,这个类负责执行预期的商业逻辑,然后将控制分派给适当的View组件来创建响应。
Struts也支持使用包含有运行框架所必需的标准属性之外的附加属性的 ActionMapping 类的能力。这允许你保存特定于你的应用程序的附加信息,同时仍可利用框架其余的特性。另外,Struts允许你定义控制将重定向到的逻辑名,这样一个行为方法可以请求“主菜单”页面(举例),而不需要知道相应的JSP页面的实际名字是什么。这个功能极大地帮助你分离控制逻辑(下一步做什么)和显示逻辑(相应的页面的名称是什么)。
2. 创建Model组件
2.1 概述
你用到的应用程序的需求文档很可能集中于创建用户界面。然而你应该保证每个提交的请求所需要的处理也要被清楚的定义。通常说来,Model 组件的开发者集中于创建支持所有功能需求的JavaBeans类。一个特殊应用要求的beans的精确特性依赖于具体需求变化会非常的大,但是它们通常可以分成下面讨论的几种类型。然而,首先对“范围”概念做一个简短的回顾是有用的,因为它与beans有关。
2.2 JavaBeans和范围
在一个基于web的应用程序中,JavaBeans可以被保存在(并从中访问)一些不同“属性”的集合中。每一个集合都有集合生存期和所保存的beans可见度的不同的规则。总的说来,定义生存期和可见度的这些规则被叫做这些beans的 范围 。JSP规范中使用以下术语定义可选的范围(在圆括号中定义servlet API中的等价物):
page - 在一个单独的JSP页面中可见的Beans,生存期限于当前请求。(service()方法中的局部变量) request - 在一个单独的JSP页面中可见的Beans,也包括所有包含于这个页面或从这个页面重定向到的页面或servlet。(Request属性)
session - 参与一个特定的用户session的所有的JSP和servlet都可见的Beans,跨越一个或多个请求。(Session属性)
application - 一个web应用程序的所有JSP页面和servlet都可见的Beans。(Servlet context属性)
记住同一个web应用程序的JSP页面和servlets共享同样一组bean集合是很重要的。例如,一个bean作为一个request属性保存在一个servlet中,就象这样:
MyCart mycart = new MyCart(...);
request.setAttribute("cart", mycart);
将立即被这个servlet重定向到的一个JSP页面使用一个标准的行为标记看到,就象这样:
<jsp:useBean id="cart" scope="request" path="/msg.jsp"/>
</action>
</action-mappings>
ActionMapping就是用来描述一个Action的URL、具体实现的文件、相对应的ActionForm
数据属性(request or session)、是否需要进行数据校验和回写、以及处理完成后可能
跳转的URL.
而ActionForward你就可以理解为Action 操作完成后的跳转URL,Action在处理完相关操作后
返回的是一个ActionForward也就是告诉Struts我做完这个操作下一步到哪儿去。
构建Struts1.1运行环境
我的配置是居于Tomcat4.0以上版本讨论,其他的AppServer大致相同。
1:得到Struts1.1
http://jakarta.apache.org/builds/jakarta-struts/release/v1.1-b1/jakarta-struts-1.1-b1.zip
2:设置
把Struts.jar Copy到$Tomcat_home/common/lib 或你使用Struts的Appaction下的WEB-INF/lib下
在你使用Struts的Appaction下web.xml中增加下列配置
<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>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<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>
<!-- Nested Tag Library Descriptor -->
<taglib>
<taglib-uri>/WEB-INF/struts-nested.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
</taglib>
<!-- Template Tag Library Descriptor -->
<taglib>
<taglib-uri>/WEB-INF/struts-template.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-template.tld</taglib-location>
</taglib>
Struts1.1中提供了很详细的例子,你可以仔细看看.
接下来你该根据需要配置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">
<struts-config>
<!-- ========== Form Bean Definitions =================================== -->
<form-beans>
<!-- Registration form bean -->
<form-bean name="useregForm"
type="com.bingo.finance.action.UserForm"/>
</form-beans>
<!-- ========== Global Forward Definitions ============================== -->
<global-forwards>
<forward name="error" path="/error.jsp"/>
</global-forwards>
<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings>
<!-- Registration Action -->
<action path="/usereg"
type="com.bingo.finance.action.UseregAction"
name="useregForm"
scope="request"
validate="true"
input="/usereg.jsp">
<forward name="success" path="/msg.jsp"/>
</action>
</action-mappings>
<!-- ========== Message Resources Definitions =========================== -->
<message-resources
parameter="com.bingo.finance.common.DisplayMsg"/>
<!-- ========== Plug Ins Configuration ================================== -->
<!-- Add multiple validator resource files by setting the pathname property -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathname" value="/WEB-INF/validator-rules.xml"/>
<set-property property="pathname" value="/WEB-INF/validation.xml"/>
</plug-in>
</struts-config>
上面的英文我相信你能够看懂。我就不做解释了。你需要继续配置validation.xml了,看如下
简单的例子.
<form-validation>
<formset>
<form name="useregForm">
<field property="username"
depends="required,mask,minlength,maxlength">
<arg0 key="common_username"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w+$</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>5</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>20</var-value>
</var>
</field>
<field property="password"
depends="required,mask,minlength,maxlength">
<arg0 key="common_password"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w+$</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>5</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>20</var-value>
</var>
</field>
<field property="nickname"
depends="required,mask,minlength,maxlength">
<arg0 key="common_nickname"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w+$</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>5</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>20</var-value>
</var>
</field>
<field property="superpass"
depends="required,mask,minlength,maxlength">
<arg0 key="common_superpass"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>^\w+$</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>10</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>20</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
上面validation.xml就是告诉Struts我的useregForm取到的数据应该做下面的验证
username是必须不能为空的并且最小长度为5,最大长度是20.
................
password,nickname,superpass基本一样我就不做更多说明.至次配置基本结束,我们要开始写
第一个Struts 了。
开发Struts1.1
usereg.jsp
为了考虑页面的灵活性,在页面中显示的所有元素我都放在properties文件中并由
com.bingo.finance.common.HtmlMsg这个文件取到.
===================================================================
<%@ page contentType="text/html;charset=GBK" %>
<%@ page import="java.io.*"%>
<%@ page import="com.bingo.finance.common.HtmlMsg"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<head>
<title><%=HtmlMsg.TITLE_REGISET%></title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<form name="usereg" method="post" action="usereg.esp">
<!--在Struts中默认的后缀是.do你可以根据需要自己修改-->
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr align="center">
<td colspan="2"><%=HtmlMsg.TITLE_REGISET%></td>
</tr>
<tr>
<td width="49%" align="right"><%=HtmlMsg.COMMON_USERNAME%>:</td>
<td width="51%">
<!--为了实现回写在Struts中建议你使用Tag使用如下写法代替一般的写法
<html:text property="username" size="20" maxlength="30" stylestyleId="userId"/>
上面的代码你看不懂你需要进一步了解Tag.
-->
<input type="text" name="username" size="20" maxlength="20">
</td>
</tr>
<tr>
<td width="49%" align="right"><%=HtmlMsg.COMMON_PASSWORD%>:</td>
<td width="51%">
<input type="password" name="password" size="20" maxlength="20">
</td>
</tr>
<tr>
<td width="49%" align="right"><%=HtmlMsg.COMMON_NICKNAME%>:</td>
<td width="51%">
<input type="text" name="nickname" size="20" maxlength="20">
</td>
</tr>
<tr>
<td width="49%" align="right"><%=HtmlMsg.COMMON_SUPERPASS%>:</td>
<td width="51%">
<input type="password" name="superpass" size="20" maxlength="20">
</td>
</tr>
<tr>
<td width="49%" align="right">
<input type="submit" name="Submit" value="<%=HtmlMsg.ACTION_REGISET%>">
</td>
<td width="51%">
<input type="reset" name="Submit2" value="<%=HtmlMsg.COMMON_RESET%>">
</td>
</tr>
</table>
</form>
</body>
</html>
UseregActiom.java
===========================================================
package com.bingo.finance.action;
//java import
import java.io.IOException;
import java.util.Locale;
//servlet import
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//struts import
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;
//finance import
import com.bingo.finance.action.UserForm;
import com.bingo.finance.manager.UserManager;
import com.bingo.finance.entity.User;
public class UseregAction extends Action {
//在Struts1.1以前使用perform
//struts1.1使用execute替代perform
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
try{
UserForm userForm=(UserForm)form;
UserManager userManager=new UserManager();
User user=userManager.formToEntity(userForm);
userManager.add(user);
//Insert into DataBase a Userinfo
}catch(Exception ex){
return mapping.findForward("error");
}
return mapping.findForward("success");
//ForWard is "/msg.jsp"
}
}
UserForm.java
=========================================================================
package com.bingo.finance.action;
import java.util.*;
import java.io.Serializable;
//servlet import
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//struts import
import org.apache.struts.action.ActionMapping;
import org.apache.struts.validator.ValidatorForm;
public class UserForm extends ValidatorForm implements Serializable{
//在Struts1.1以前通常Form继承ActionForm
//实际上ValidatorForm是继承ActionForm
//为什么要加一层ValidatorForm是为了校验而做的
private String id;
private String username;
private String password;
private String nickname;
private String superpass;
public UserForm(){
}
/****/
public String getId(){
return this.id;
}
/****/
public void setId(String _id){
this.id=_id;
}
/****/
public String getUsername(){
return this.username;
}
/****/
public void setUsername(String _username){
this.username=_username;
}
/****/
public String getPassword(){
return this.password;
}
/****/
public void setPassword(String _password){
this.password=_password;
}
/****/
public String getNickname(){
return this.nickname;
}
/****/
public void setNickname(String _nickname){
this.nickname=_nickname;
}
/****/
public String getSuperpass(){
return this.superpass;
}
/****/
public void setSuperpass(String _superpass){
this.superpass=_superpass;
}
/**show this class info**/
public String toString(){
StringBuffer info=new StringBuffer();
info.append("....id is:"+id);
info.append("....username is:"+username);
info.append("....password is:"+password);
info.append("....nickname is:"+nickname);
info.append("....superpass is:"+superpass);
return info.toString();
}
public void reset(ActionMapping mapping, HttpServletRequest request) {
id=null;
username=null;
password=null;
nickname=null;
superpass=null;
}
}
UserManager.java ,User.java文件我就不提供了,这一部分在实际的开发当中根据需要自己去
处理,也就是为了把数据插入数据库。
现在一个简单的注册用户你就开发完成了。很简单吧。呵呵,继续努力...但其中还有很多
细节你需要进一步了解,我只把你领到门了,你必须自己去研究一些东西,比如说,我希望
我的用户多一个Email字段和一个年龄字段我应该如何做,而且我希望validation.xml的验证
有Email合法验证,年龄必须大于0而且一定是整数。那我应该如何做?
我只能告诉你加两个字段你需要修改Form 增加字段,同时相应文件也要修改。在struts中
Email的验证非常简单。好好看例子吧,好好研究validator-rules.xml,这个我认为struts1.1
最好的功能增加(Struts1.0没有这个文件)。Struts中提供了一个非常灵活而且重用极高的验证机制。
Struts和其他开发方式的比较
使用Struts开发至少带来如下好处:
1:层次结构非常清晰,也使得分工很明确。
2:重用度很高,连数据验证都可以重用,还有一个更好的重用就是Form,Action是可以很好的重用的。
3:可维护性好。这是居于第一点的。
.................
下面我说一个Struts的不足之处,如果你使用或者了解TDK你就会觉得,TDK中可以自动生成很多
java源代码的确可以节省不少工作量,Struts中也可以做的很好。我自己开发了一个工具,功能
还不够强大。在我的计划当中,我希望Form,JavaBean(封装数据相当于EJB中的Entity Bean),
甚至包括操作数据库的Method都自动生成,还有validation.xml也可以动态的生成。然而因为
下一个原因:Struts到目前为止还不是一个比较成熟的项目。他的改动实在是太大了。1.0和0.5
就有很大的改动。所以我的计划有变。我希望在1.1完全推出来再做开发(1.1现在是Beta版)。
同时我也给Craig R. McClanahan(Struts开发的Team leader)写过信听取他的建议.
-完-
本文来自: 中国自学编程网(www.zxbc.cn) 详细出处参考:http://zxbc.cn/html/20070608/22526.html