Struts MVC框架
Web应用的分层
交互层(Interaction Layer),表现数据,收集数据,也就是视图层,
接受请求,通过处理层完成相应的响应。(V,C)
处理层(Processing Layer),完成数据的处理,也就是业务层
(M)。
MVC设计模式(应用观察者模式的框架模式)
M: Model(Business process layer),模型,操作数据的业务处理层,
并独立于表现层(Independent of presentation)。
V: View(Presentation layer),视图,通过客户端数据类型显示数
据,并回显模型层的执行结果。
C: Controller(Control layer),控制器,也就是视图层和模型层桥
梁,控制数据的流向,接受视图层发出的事件,并重绘视图。
MVC框架的实现模型
模型一(Page-centric):
JSP+JavaBean,JSP既充当控制,又充当视图,以页面为核心,
1JSP使用jsp:useBean,它不能够实现不同的页面,显示不同的数
据,需要借助于中间类来调用JavaBean的方法才能实现。
模型二(Servlet-centric):
JSP+Servlet+JavaBean,以控制为核心,JSP只负责显示和收集数
据,Sevlet,连接视图和模型,将视图层数据,发送给模型层,
JavaBean,分为业务类和数据实体,业务类处理业务数据,数据
实体,承载数据,基本上大多数的项目都是使用这种 MVC的实现
模式。
StrutsMVC框架(Web application frameworks)
Struts是使用MVC的实现模式二来实现的,也就是以控制器为核
心。
Struts提供了一些组件使用MVC开发应用程序:
Model:Struts没有提供model类。 这个商业逻辑必须由Web应用程
序的开发者以JavaBean或EJB的形式提供
View:Struts 提供了 action form 创建 form bean, 用于在
controller和view间传输数据。 此外,Struts提供了自定义JSP标
签库,辅助开发者用JSP创建交互式的以表单为基础的应用程序,
2应用程序资源文件保留了一些文本常量和错误消息,可转变为其
它语言,可用于JSP中。
Controller:Struts提供了一个核心的控制器 ActionServlet,通
过这个核心的控制器来调用其他用户注册了的自定义的控制器
Action,自定义Action需要符合Struts的自定义Action规范,还
需要在struts-config.xml的特定配置文件中进行配置,接收 JSP
输入字段形成Action form,然后调用一个Action控制器。Action
控制器中提供了model的逻辑接口。
写一个基于Struts的web应用
1,创建一个符合标准的 web应用的结构,也就是一个有 WEB-INF
文件夹的应用文件夹,在应用中需要使用到Struts的一些jar文
件,要放到WEB-INF的lib文件夹下,这些jar文件都在struts的
zip 文 件 中 的 /struts-1.2.9-bin/lib 下 还 有 struts-1.2.9-
bin/contrib/struts-el/lib 下 的 standard.jar 、 jstl.jar 和
struts-el.jar。
2,在web.xml中配置Struts的核心控制器ActionServlet,并指明
Struts的配置文件的所在位置WEB-INF下,在struts的文件中有
一个样板的web.xml文件,使用这个web.xml文件来部署应用就可
以了 ,这个样板在struts的zip文件中的struts-1.2.9-src.zip文
3件中的web/examples/WEB-INF/web.xml就是样板文件。 部署应用看
struts是否发布成功。
<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>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
3,写JSP页面和业务,实体,和自定义控制器类 Action,自定义
Action是要继承于Action类
例:
import org.apache.struts.action.*;
import javax.servlet.http.*;
4public class LoginAction extends Action{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest
request,HttpServletResponse response) throws Exception
{
if(request.getParameter("userName").equals("admin")&&
request.getParameter("passwd").
equals("123")){
return mapping.findForward("success");
}
return mapping.findForward("fail");
}
}
在struts-config.xml文件中的配置,解析配置文件中,配置文件的
action标签就会被映射成ActionMapping对象。
<struts-config>
<form-beans>
<form-bean name="xxx" type="ActionForm的类全名">
5 <form-bean name="LoginForm" type="basic.LoginForm">
</form-beans>
<action-mappings>
<action path="/basic/login"
type="alan.struts.basic.LoginAction"
name="xxx" scope="request|
sessio(默认值)">
<forward name="success" path="/basic/success.jsp"
redirect="true"/>
<forward name="fail" path="/basic/fail.jsp"
redirect="false"(重定向,默认false)/>
</action>
<action path="action的路径,在form的action中写的那个
路径" type="action的类全名">
<forward name="在自定义的Action中使用的findForward
方法的参数" path="跳转页面的路径"/>
<forward name="xxx" path="xxx/xxx.jsp"/>
</action>
</action-mappings>
</struts-config>
ActionForm是可以自动将表单中的数据封装成对象,当然,一个
6自定义 ActionForm 也是要遵守 Struts 规范的,也就是要继承于
ActionForm,并在以上的struts-config.xml进行配置。
ServletController(ActionServlet 和自定义的 Action),配置
Ctrler需要配置struts-config.xml,通过客户端form的action来
查找调用相应的action,自定义action中的mapping对应的是配置
文件中的forward标签,通过forward的path属性来跳转到相应
的路径。
基于struts的web应用的开发步骤
1. 对应用环境进行配置
2. 创建web应用的结构,需要将struts应用的jar文件进行
部署。
3. 在web服务器部署struts
4. 配置struts-config.xml文件,配置Action
5. 写自定义Action,实体,以及业务类
ActionForm的校验
<struts-config>
<form-beans>
7 <form-bean name="xxx" type="ActionForm的类全名">
<form-bean name="LoginForm" type="basic.LoginForm">
<!--配置ActionForm类-->
</form-beans>
<action-mappings>
<action path="/basic/login"
type="alan.struts.basic.LoginAction"
name="xxx" scope="request|sessio(默认值)
Form的保存空间">
<forward name="success"
path="/basic/success.jsp"/>
<forward name="fail" path="/basic/fail.jsp"
redirect="false"(重定向,默认false)/>
</action>
<action-mappings>
</struts-config>
ActionForm 的校验是 struts 提供的一项类似于 Javascript 的
表单校验的功能。他可以验证用户填写的表单数据的正确性。
ActionForm的校验,如果表单中的数据符不符合规定格式的要
求,ActionForm的validate()方法会返回一个ActionError对象,
8ActionError对象中封装了一个或多个应用发现的校验错误,每一
个错误有一个 ActionMessage 对象表达,我们可以通过判断这个
ActionError的对象是否为空,如果为空那么表单的数据符合格式
要求,不为空就是表单项中就有不符合格式要求的项。
struts标签
在使用struts标签的JSP页面中要先加上以下的标签库的引用
<%@taglib uri="http://struts.apache.org/tags-html"
prefix="html" %>
<%@taglib uri="http://struts.apache.org/tags-bean"
prefix="bean" %>
<bean:message key="errors.username.required">这个标签可以
从指定的资源文件中根据指定的key值来取得可以对应的值,但是
需要在struts-config.xml中进行配置。
配置资源,这些资源可以在ActionMessage中使用,也就是在
构造ActionMessage是指定资源文件中的key这样,在发现校验错
误时,就可以先在资源文件中指定的key的值了。可以使用struts
的<html:errors>
<html:message>、<bean:message>标签都可以显示指定错误的消
息。
9<struts-config>
.....
<message-resources
parameter="alan.struts.message.MessageResource" />
<!--使用message标签时配置资源文件的位置-->
</struts-config>
struts会自动的判断返回ActionError是否为空,如果是空可
以自动的转向指定页面,也可以强制不进行校验,虽然可以在
Form中不去覆盖validate()方法,但是那样是不可取的。要实现上
面提得到功能还需要在struts-config中配置。
<action path="/basic-validate/login"
type="alan.struts.basic.LoginAction"
name="loginValidateForm" scope="request"
validate="true" input="/basic-
validate/login.jsp">
<!--scope可以指定Form的存放空间,默认为sessoin-->
<!--action标签中配置validate="false"可以不进行校验,
input是指定校验出错跳转的页面-->
<forward name="success" path="/basic-
validate/success.jsp"/>
<forward name="fail" path="/basic-
10validate/fail.jsp"/>
</action>
<html:message id="error"><!--id 属性是ActionMessage存放在
空间中的key-->
<h1>${error}</h1>
</html:message>
<html:errors> 标 签 只 会 原 样 输 出 在 ActionErrors 中
ActionMessage对应资源文件中对应的值。
<html:messages> 标 签 还 可 以 对 输 出 在 ActionError 中
ActionMessage对应资源文件中对应的值作一些显示效果的修改。
<bean:message key="xxx.xxx">标签只会取资源文件中指定 key
所对应的值,使用bean:message标签可以实现国际化。
struts的html标签
struts的html标签的使用类似于html标签,但是少有区别,
指定类型的方式变成使用不同的标签,这样会绑定 struts,所以
旨在需要时使用。
<html:form method="post" action="/basic-validate/login">
<!--
11 struts 的 html 标 签 中 的 action 可 以 只 写 转 到 的
actionpath,struts会在解析是自动添加需 要的部分
-->
<html:text property="userName" />
<html:password property="password" redisplay="false"/>
<!--redisplay="false" 不 进 行 回 写 , 只 有
html:password标签可用-->
<html:radio property="hibbos">
<html:submit value="login" />
</html:form>
Struts预定义的Action类
注意:在使用继承 Struts预定义的Action类,一定不要覆盖
execute方法,否则会导致无法调用自定义Action相应方法。
DispatchAction类(org.apache.struts.actions.DispatchAction)
DispatchAction 类是 Action 类的子类,他提供了有实现的
execute方法。
我们写的自定义Action类,可以继承DispatchAction类,但不
12要覆盖execute方法,可以在自定义类中写反回值和参数表都与
execute方法相同的方法,可以通过在struts-congfig.xml中为这
个action的配置中添加一个参数,来判断调哪一个方法,实际上
DispatchAction类就是通过反射机制,通过form中参数调用了自
定义Action中的方法,当然这些方法的定义要符合规范,使用继
承 DispatchAction 类的自定义的 Action 类,也就会共享同一的
Action路径。
注意:使用继承DispatchAction类的自定义的Action,只会匹
配一个action路径,只能共享一个ActionForm,如果加上校验,
会产生form表单的参数不一致的情况,会导致校验无法通过。
例:
public class MyAction extends DispatchAction{
ActionForward add(ActionForm form,HttpServletRequest
request,HttpServletResponse
response ActionMapping mapping) throws Exception
{
return mapping.findForward("sucess")
}
}
13<action path="/add" type="MyAction"
parameter="methodName">
<!--parameter属性是和form中隐藏域的名字相对应的--
>
<forward name="sucess" path="/sucess.jsp"/>
</action>
<from action="add.do" method="post">
<input type="hidden" name="methodName" value="add"/>
<!--
使用隐藏域为 struts传递要调用自定义 Action中方法
的方法名,是通过与struts-config.xml
中action标签中的parameter和name属性相对应来获
取隐藏域的value。
-->
<input type="submit" value="submit"/>
</from>
MappingDispatchAction 类
(org.apache.struts.actions.MappingDispatchAction)
14MappingDispatchAction 类是 DispatchAction 的子类,他和
DispatchAction不同点就是可以去匹配多个action路径,这样也
就是结决了共用ActoinForm的校验问题了,多个Action的路径使
用同一的自定义Action类,这样就不用共享同一个 ActionForm,
也就不会有校验问题了。
例:
public class MyAction extends MappingDispatchAction{
ActionForward add(ActionForm form,HttpServletRequest
request,HttpServletResponse
response ActionMapping mapping) throws Exception
{
return mapping.findForward("add")
}
ActionForward del(ActionForm
form,HttpServletRequest request,HttpServletResponse
response ActionMapping mapping) throws Exception
{
return mapping.findForward("del")
}
}
15<action path="/add" type="MyAction" parameter="add">
<!--parameter属性是指定调用方法的名字-->
<forward name="add" path="/add.jsp"/>
</action>
<action path="/del" type="MyAction" parameter="del">
<forward name="del" path="/del.jsp"/>
</action>
在JSP页面中也不用在使用隐藏域传递参数,直接在form中的
action中就可以直接使用xxx.do匹配了。
<form action="add.do" method="post">
<input type="submit" value="submit"/>
</form>
<form action="del.do" method="post">
<input type="submit" value="submit"/>
</form>
LookupDispatchAction(org.apache.struts.actions.LookupDispa
tchAction)
LookupDispatchAction类也是DispatchAction类的子类,他所
16实现的功能是解决一个表单多种提交问题的
,他是通过使用资源文件,用submit按钮的value来作为资源
文件中的key所对应的值,通过这个值来找到对用的 key,在使用
这个key来获得指定Map中所对应的值,这个值就是要调用的方法
名。
submit 的 value---->MessageResource.properties 中 的
key----->Map中key对相应的值---->action
例:
<%@taglib uri="http://struts.apache.org/tags-bean"
prefix="bean" %>
<form method="post"
action="${pageContext.request.contextPath}/lookup/adddel.do">
<input type="submit" value="<bean:message key="button.add"
/>" name="methodName">
<!--注意name="methodName"是和strut-config.xml中
action标签中的parameter属性-->
<input type="submit" value="<bean:message
key="button.delete" />" name="methodName">
</form>
17MessageResource.properties
button.add=add new user
button.delete=delete user
注 意 : 在 继 承 LookupDispatchAction 时 , 要 覆 盖
getKeyMethodMap()方法,并定义Map,向Map中放入指定的键值对。
public class AddDelLookupDispatchAction extends
LookupDispatchAction
{
public Map getKeyMethodMap(){
Map keyMethodMap= new HashMap();
keyMethodMap.put("button.add", "add");
keyMethodMap.put("button.delete", "delete");
return keyMethodMap;
}
public ActionForward add(ActionMapping
mapping,ActionForm form,
HttpServletRequest
request,HttpServletResponse response) throws Exception
18 {
return mapping.findForward("add");
}
public ActionForward delete(ActionMapping
mapping,ActionForm form,
HttpServletRequest
request,HttpServletResponse response) throws Exception
{
return mapping.findForward("delete");
}
}
<action path="/lookup/adddel"
type="alan.struts.actions.AddDelLookupDispatchAction"
parameter="methodName">
<forward name="add" path="/add.jsp"/>
<forward name="delete" path="/delete.jsp" />
</action>
<message-resources
parameter="alan.struts.message.MessageResource" />
自定义的Action类的一些规则
191,尽量不要在Action类中使用(静态)成员变量,如果使用
要加上同步。
2,尽量使各模块间的耦合性降低,最大限度的针对接口编程。
3,可以将共代码方在覆盖父类的方法中,最后可以用
super.xxx(xxx)来调用父类的方法,使用父类的实现,并加上了自
定义的功能。
Struts的Token(令牌)机制
Struts使用Token机制,来防止恶意的破坏和重复提交问题,
也就是点击后退后在再提交,这是Struts无法发现的,在form中
生成一个token码,在session中也报村有一个同样的token码,
当表单提交后,判断两个token码向等后,就会改变session中的
这个token码,当然在用回退后,form的token码是不会变的,
在提交,还会判断两个token码是否相等,如果不等就会抛出异常,
证明这是过时的垃圾数据。
void saveToken(HttpServletRequest request)方法用于将在客
户端生成的token码,保存在session中。
void resetToken(HttpServletRequest request)方法用于重置
token码,生成新的token码。
20boolean isTokenValid(HttpServletRequest request,boolean
reset)判断token码是否相等,并且是否重置token码。reset是设
定是否重置token码,一般设为true。
设置token码
public ActionForward toadd(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)throws Exception
{
saveToken(request);
return mapping.findForward("next");
}
验证token码
public ActionForward add(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)throws Exception
{
if(isTokenValid(request, true)){
request.setAttribute("message",
21"contratulation!");
} else {
request.setAttribute("message", "sorry");
}
return mapping.findForward("next");
}
Struts的异常处理
Struts只处理action的异常,
配置struts的异常处理
全局的异常处理
<global-exceptions>
<exception key="error" path="xxx/xxx"
type="xxx.xxx.Xxxx">
</global-exceptions>
<action path="xxx/xxx" type="xxx.xxx.Xxxx">
....
<exception key="xxx" path="xxx/xxx" type="xxx.xxx.Xxxx">
22</action>
在 exception 标签中的 key,也就是在出现异常时会封装在
ActionErrors中,也就是可以在页面中使用。
ActionError(String key, Object value0),可以通过在构造
ActionError 时,指定不同的 key 值来对异常进行分类,并且在
html:error标签的
自己构造ActionErrors并使用下面的方法发送
void saveErrors(HttpServletRequest request,ActionErrors
errors)这个方法用以把封装了异常的ActionErrors的key存储到
request中。
Struts动态Form
DynaActionForm,动态的 ActionForm,动态的 form 不需要去写
特定的ActionForm类,只需要在配置文件中配置好form中的属性
名和属性类型。以,Struts会自动的封装成动态的Form。
<form-bean name="xxx"
type="org.apache.struts.action.DynaActionForm">
<from-property name="xxx" type="xxx.xxx.xxx">
23 <from-property name="xxx" type="xxx.xxx.xxx">
...
...
</form-bean>
动态的ActionForm的使用上和普通的ActionForm相同。
在Struts中的Form要是粗粒度的,不要写太多的 Form,要根
据情况确定Form的多少。
Struts的动态校验
Struts可以通过继承DynaActionForm,并覆盖validate()方法
来打倒校验的目的。 也可以通过配置校验规则来进行动态Form的校
验实质上就是翻译成javasctipt代码。
使 用 校 验 规 则 来 进 行 动 态 校 验 时 需 要 写
validation.xml,validator-rules.xml
还需要对struts-config.xml进行配置
validation.xml
<form-validation>
<formset>
<form name="/token/add">
24 <field property="name" depends="required,minlength,
maxlength">
<arg0 key="token.name" />
<arg1 name="minlength" key="${var:minlength}"
resource="false"/>
<arg1 name="maxlength" key="${var:maxlength}"
resource="false"/>
<var>
<var-name>minlength</var-name>
<var-value>5</var-value>
</var>
<var>
<var-name>maxlength</var-name>
<var-value>8</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
struts-config.xml
25<plug-in
className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-
INF/validation.xml"/>
</plug-in>
Struts的标签
bean,html,logic标签库,在Struts的标签也支持JSP2.0的
EL表达式。
bean标签库
<bean:... >
bean标签库,是用来访为JavaBean的属性或者是为Bean的属
性赋值,创建JavaBean,类似于JSP中的jsp:useBean动作的功能。
bean标签库中的标签中大部分都有以下的属性
id="xxx" 指定Bean的名字标识,Bean在被读出后将引用保存在
以这个id命名的对象中,也就是在JSP中使用的变量的引用。
name="xxxx"指定要读取Bean的名字
26property="xxxx"
scope="page|request|session|application"
资源读取标签
<bean:resource>读取资源文件
<bean:cookie>使用这个标签可以对Cookie进行操作
<bean:header>读取header信息
例:
<bean:resource id="indexpage" name="index.jsp"/>
<bean:write name="indexpage"/>
<bean:head id="head" name="user-agent"/>
<bean:write name="head"/>
<bean:cookie id="testcookie" name="/taglib/bean-cookie"
value="emptyValue"/>
<%
if(testcookie.getValue.equals("emptyValue")){
javax.servlet.http.Cookie cook=new
javax.servlet.http.Cookie("/taglib/bean-cookie","taglib
cookie");
27 cook.setComment("test");
cook.setMaxAge(3600);
response.addCookie(cook);
}
%>
可以将资源写到页面的标签
<bean:write>将Bean的属性加入到输出流中
<bean:write name="xxx"/>name 属性是要加入的资源,也就是
先前在其他资源标签中的id属性定义的名字
<bean:define>定义变量
例:<bean:define id="test" value="test in Struts">
<bean:write name="test"/>
<bean:message>读取消息,可以根据key读取消息。
例:
<bean:message key="org.test">
html标签库
<html:form>
28对应html中的<form>,使用<html:form>会将表单中的属性自
动封装成Form,他的action属性可以直接写struts的配置文件中
的path
<html:text>、 <html:password>、 <html:textarea>、 <html:hidden>
、<html:submit>
<html:reset>、 <html:checkbox>、 <html:radio>、 <html:select>、 <
html:option>
以上者写标签的使用是和html中的form相对应的。
<html:options>这个标签用来表示一组选择项
<%
java.util.ArrayList list=new java.util.ArrayList();
list.add(new org.apache.struts.util.LabelValueBean("show
value","value"));
list.add(new org.apache.struts.util.LabelValueBean("show
value1","value1"));
pageContext.setAttribute("vlauelist" list);
%>
<html:form action="xxx.do">
29 <html:select property="test">
<html:options collection="valuelist" property="value"
labelProperty="label"/>
</html:select>
</html:form>
Struts的Tiles框架
Tiles是一个框架,他实现了页面的复合视图,页面代码中不仅
有数据,也有页面的布局格式。
要在基于 Struts 应用中使用 Tiles 框架,就要在 struts-
config.xml中配置
<plugin className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definintions-config"
value="/WEB-INF/tiles-defs.xml">
<!--定义tiles布局文件tiles-defs.xml-->
</plugin>
tiles的布局配置文件tiles-defs.xml
30<tiles-definitions>
<!-- 页面基本布局-->
<definition name="pms_base"
path="/common/pms_layout.jsp">
<put name="title" value="pms title" />
<put name="header" value="/common/header.jsp" />
<put name="body" value="some body page" />
<put name="footer" value="/common/footer.jsp" />
</definition>
<!-- 其他页面定义-->
<definition name="add" extends="pms_base">
<put name="title" value="add" />
<put name="body" value="/person_add.jsp" />
</definition>
</tiles-definitions>
在struts-config.xml中要把forward的配置更改一下
<action path="/person/toadd"
type="alan.pms.action.PersonAction"
name="personForm" scope="request"
parameter="toAdd">
<forward name="add" path="add"/>
31</action>
这样就会使页面加上header.jsp和footer.jsp显示在配置好的
页面中
在页面中使用 tiles 标签时,要引入标签库,<%@taglib
uri="/WEB-INF/tiles.tld" prefix="tiles"%>
<tiles:insert page="xxx.jsp">
<tiles:put name="header" value="header.jsp">
<tiles:put name="footer" value="footer.jsp">
</tiles:insert>
在struts-config.xml中要把forward的配置更改一下
<action path="/person/toadd"
type="alan.pms.action.PersonAction"
name="personForm" scope="request"
parameter="toAdd">
<forward name="add" path="add"/>
</action>
32