Struts 1.x

来源:互联网 发布:藏头诗制作软件 编辑:程序博客网 时间:2024/05/30 12:30

--------------------------Struts 1.x理论介绍--------------------------

1.   MVC设计模式

(1)模型-视图-控制器(Model-View-Controller)是80年代出现的一种软件设计模式,现在已经被广泛的使用。它强制的把应用程序的输入、处理、输出分开,三个核心模块M-V-C分别负担不同的任务。

(2)模型(Model)模型是应用程序的主体部分。模型表示业务数据和业务逻辑,一个模型可以为多个视图提供数据,提高了应用的可重用性。

(3)视图(View)用程序中用户界面相关的部分,视图向用户显示数据,并能接收用户的输入数据,但它并不进行任何实际的业务处理。

(4)控制器(controller)工作就是根据用户请求,调用相应的模型组件处理请求,然后调用相应的视图显示模型返回的数据。

(5)MVC 的出现不仅实现了功能模块和显示模块的分离,同时它还提高了应用系统的可维护性、可扩展性、可移植性和组件的可复用性。

2.   为什么要使用struts

首先,struts是建立在MVC这种公认的好的模式上的,StrutsMVC上都有涉及,但它主要是提供一个好的控制器和一套定制的标签库上,也就是说它的着力点在C V上,因此,它天生就有MVC所带来的一系列优点,如:结构层次分明,高可重用性,增加了程序的健壮性和可伸缩性,便于开发与设计分工,提供集中统一的 权限控制、校验、国际化、日志等等;

其次,它是个开源项目得到了包括它的发明者Craig R.McClanahan在内的一些程序大师和高手持续而细心 的呵护,并且经受了实战的检验,使其功能越来越强大,体系也日臻完善

最后,是它对其他技术和框架显示出很好的融合性,大大提高了开发速度

3.   Framework的概念

人们用于解决相同或者相似类型问题的方案

特点:可重用性,可扩展性,可收缩性

基于请求响应(Request-Response)模式的应用Framework的逻辑结构

控制器(Controller)

业务逻辑层(Business Logic)

数据逻辑层(Data logic)

4.   Struts的概念和体系结构

(1)StrutsApache组织的一个开源项目,主要是采用ServletJSP技术来实现的,基于Sun Java EE平台的MVC框架,它采用MVC模式,将MVC模式分离显示逻辑和业务逻辑的能力发挥得淋漓尽致

Struts由一组相互协作的类、Serlvet以及丰富的标记库(jsp tag lib)和独立于该框架工作的实用程序类(Validator)组成。

(2)Struts有其自己的控制器(Controller),同时整合了其他的一些技术去实现模型层(Model)和视图层(View)。在模型 层,Struts可以很容易的与数据访问技术相结合,包括EJB,JDBCObject RelationBridge。在视图层,Struts能够与JSP, VelocityTemplates,XSL等等这些表示层组件想结合。

(3)Struts frameworkMVC模式的体现,下面我们就从分别从模型、视图、控制来看看struts的体系结构(Architecture)。下图显示了struts framework的体系结构响应客户请求时候,各个部分工作的原理。

从视图角度(View

主要由JSP建立,struts自身包含了一组可扩展的自定义标签库(TagLib),可以简化创建用户界面的 过程。目前包括:Bean TagsHTML TagsLogic TagsNested TagsTemplate Tags 这几个Taglib。有关它们的详细资料请参考struts用户手册

从模型角度(Model)

模型主要是表示一个系统的状态(有时候,改变系统状态的业务逻辑操作也也划分到模型中)。在 Struts中,系统的状态主要有ActiomForm Bean体现,一般情况下,这些状态是非持久性的。如果需要将这些状态转化为持久性数据存储,Struts本身也提供了Utitle包,可以方便的与数据 库操作

从控制器角度(Controller

Struts framework中, Controller主要是ActionServlet,但是对于业务逻辑的操作则主要由ActionActionMapping ActionForward这几个组件协调完成(也许这几个组件,应该划分到模型中的业务逻辑一块)。其中,Action扮演了真正的业务逻辑的实现者, ActionMappingActionForward则指定了不同业务逻辑或流程的运行方向。

 

 

--------------------------Struts 1.x环境配置--------------------------

下载strutsjar包,从Apache 的官方网站 http://www.apache.org/ 中下载

选择 Download--Backup Sites下的http://www.apache.org/dist/--struts--binaries,可以找到有关struts 1.x的不同版本

 

1.   搭建环境

(1)   导入jar

(2)   WEB-INF下建立配置文件:struts-config.xml

(3)   web.xml文件中注册struts中心控制器--ActionServlet,以及说明struts-config.xml配置文件的位置

(4)   超链接

struts-config.xml文件

web.xml示例

2.   配置FormBean

(1)   创建一个类,继承ActionForm

(2)   struts-config.xml中注册该FormBean

 <form-beans >

<form-bean name="userForm"type="com.yourcompany.struts.form.UserForm"/>

</form-beans>

属性name是变量名

属性type是类全名

3.   配置Action

(1)   创建一个类,继承Action

覆盖execute方法,该方法是Action中的缺省方法,调用Action的时候先寻找execute方法,其他的方法都会被无视掉

(2)   struts-config.xml中注册该Action

        <action-mappings >

             <action path="/login"

type="com.Action.UserAction"

               name="userForm"

              <forward

                    name="success"

                    path="/success.jsp"

                   redirect="true" />

</action>

 </action-mappings>

属性path指明(调用者)jsp能通过中心控制器ActionServlet找到该Action

属性type表示该Action类全名

Name表示该Action引用的FormBean的名称

 

JSP或静态页面中

使用struts格式的html语言,表单中的action应该=/注册的Action名称

使用普通格式的html语言,表单中的action应该=/注册的Action名称.do

4.   Struts-config.xml配置文件的元素格式规范

The content of element type“struts-config” must match

”(display-name?,description?,data-sources?,form-beans?,global-exceptions?,global-forwards?,action-mappings?,controller?,message-resources*,plug-in*)”

这是在MyEclipse环境下这样来定义的,所以使用此IDE时就必须遵守这个规范

5.   问题总结

(1)   谁来填充Form?什么时候填充?根据什么来填充

(2)   ActionServlet怎样把请求派发给Action

(3)   Action运行完后怎样跳转?

 

 

------------------------Struts1.x的工作原理------------------------

Struts工作原理图示例

1.   读取配置

Struts框架总控制器ActionServlet本质上是一个Servlet,在web.xml中配置成自动启动的Servlet

读取配置文件struts-config.xml的配置信息,为不同的struts模块初始化相应的ModuleConfig对象:

ActionConfigControlConfigFormBeanConfigForwardConfigMessageResourcesConfig

2.   发送请求

用户提交表单或调用URLWEB应用程序服务器提交一个请求,请求的数据用HTTP协议上传给web服务器

3.   填充FormBean

*.do请求从ActionConfig中找出对应请求的Action子类,如没有对应的Action,控制器直接转发给JSP或静态页面。

如果有对应的Action且这个Action有一个相应的ActionForm,实例化该ActionForm并用JSP或静态页面中的HTTP请求的数据(例如注册信息,帐号、密码、姓名等)来填充ActionForm的属性,且保存在ServletContext(requestsession),这样他们就可以被其他Action对象或者JSP调用

4.   派发请求

控制器根据配置信息ActionConfig将请求派发到具体的Action,并把相应的FormBean也传给该Actionexecute()方法

5.   处理业务

Action一般只包含一个excecute()方法,它负责执行相应的业务逻辑(调用其他业务模块)

完成后返回一个ActionForward对象,控制器通过该ActionForward对象来进行跳转工作

6.   返回响应

Action根据业务处理的不同结果返回一个目标响应对象给总控制器,该目标响应对象对应一个具体的JSP页面或另一个Action

这个响应不是真正的响应目标,只是响应目标的一个关键字

7.   查找响应

总控制器根据执行业务功能由Action返回的目标响应对象,找到对应的资源对象,通常是一个具体的JSP页面。

8.   响应用户

目标响应对象(JSP)将结果页面展现给用户

 

 

--------------------------Action的研究与分析--------------------------

1.   Action在发出该Action的请求时初始化,而不是在读取配置时初始化

2.   每个Action只会初始化一次

3.   Action是线程不安全的,因为所有的请求共享一个Action实例

4.   怎样实现Action的安全性编程

(1)   注意不要用实例变量或者类变量共享只是针对某个请求的数据

(2)   注意资源操作的同步性

 

 

-----------------------ActionMapping的研究与分析-----------------------

1.   struts-config.xml配置文件中的每一个<action>元素都与类org.apache.struts.action.ActionMapping的一个实例对应

2.   Action中利用ActionMapping来获取struts-config.xml配置文件的信息

String name=mapping.getName();

String path=mapping.getPath();

String type=mapping.getType();

System.out.println("name="+name+"/tpath="+path+"/ttype="+type);

String[] forwardNames=mapping.findForwards();

for(String forwardName:forwardNames){

       ActionForward forward=mapping.findForward(forwardName);

       String forwardPath=forward.getPath();    

System.out.println("forwardName="+forwardName+"/tforwardPath="+forwardPath);

}

3.   struts-config.xml文件中的配置信息只能在该文件中做修改,而利用ActionMappingsetPath()方法来更改配置信息只会引起一个异常告诉用户该配置已经被冻结,这是一种保护思想,不想让用户更改从而用异常来封装它

4.   struts-config.xml

<action

attribute="userForm" input="/user.jsp" name="userForm"path="/user" type="com.user.UserAction"validate="true">

         <forward name="suc" path="/sucess.jsp"redirect="true" />

</action>

Attribute属性用来存取form的关键字,缺省值与name一样

5.   Validate属性用于控制是否校验表单,true—校验,false—不校验

默认为true

6.   Input属性结合validate=true来使用,如果validate=false,不使用校验,则input属性无效,如果validate=true且表单校验失败则跳转到该input值所代表的目标模块

 

强制让validate()方法校验失败

public ActionErrorsvalidate(ActionMapping mapping,

           HttpServletRequest request) {

       ActionErrors errors=new ActionErrors();

       ActionMessage message=new ActionMessage("error");

       errors.add("error",message);

       return errors;

}

 

Struts-config.xml文件

<action

attribute="userForm" input="/error.jsp" name="userForm"path="/user" type="com.user.UserAction"validate="true">

         <forward name="suc" path="/sucess.jsp" redirect="true" />

</action>

7.   全局跳转

有两个或两个以上的Action都需要使用的Forward,可以配置为全局跳转

所有的Action都可以向一个页面进行跳转,减少了重复跳转操作的代码量

<global-forwards>

<forward name="index"path="/index.jsp"></forward>

</global-forwards>

 

-----------------------ActionForward的研究与分析-----------------------

1.   ActionForward对象封装了跳转的URL路径且被请求处理器用于识别目标视图

2.   ActionForward的名字是独一无二的

3.   ActionForward的跳转方式

(1)   默认redirect=false,使用RequestDispatcher.forward方法跳转,是一种容器内跳转

(2)   如果在struts-config.xml配置文件中设置redirect=true,则使用HttpServletResponse.sendRedirect()方法跳转,该跳转方式也是一种容器外跳转,可以将path地址写为一个网址、例如path=”http://www.google.com”,当跳转的时候就会链接到该网站上

 

 

------------------------ActionForm的工作流程分析-----------------------

处理ActionForm的一般步骤

1.   检查Action的映射,确定Action中已经配置了对ActionForm的映射

2.   根据name属性,查找formbean的配置信息

3.   检查Actionformbean的使用范围,确定在此范围下(request,session),是否已经有次formbean的实例

4.   加入当前范围下,已经存在了此formbean的实例,而是对当前请求来说,是同一种类型的话,那么就重用

5.   否则,就重新构建一个formbean的实例(调用构造方法),并且保存在一定作用范围

6.   Formbeanreset()方法被调用,可以设置每个属性在JSP或静态页面里对应的文本框等控件中的初始值

7.   调用对应的setter方法,对状态属性赋值

8.   如果validate的属性设置为true,那么就调用formbeanvalidate()方法

9.   如果validate()方法没有返回任何错误,控制器将ActionForm作为参数,传给Action实例的execute()方法并执行

注意:直接从ActionForm类继承的reset()validate()方法,并不能实现什么处理功能,所以有必要自己重新覆盖

 

 

-------------------------ActionForm的研究与分析------------------------

1.   Scope缺省值是session

(1)   session中获取ActionForm

UserForm userForm=request.getSession().getAttribute("userForm");

(2)   request中获取ActionForm

UserForm userForm=request.getAttribute("userForm");

2.   JSP或静态页面表单中中注册信息项,例如我要注册IDnamepassword,那么

<html:form action="/user">

    id : <html:text property="id"/><br/>

    name : <html:text property="name"/><br/>

password : <html:text property="password"/><br/>

    <html:submit/><html:cancel/>

</html:form>

 

这三个属性的property属性对应的值就与ActionForm中的setXXX方法相对应,而不是与ActionForm中的属性名称对应,即使属性叫id1name1pwd也可以,只要方法名与property属性值相等即可。

 

 

-----------------------------Struts标签库-----------------------------

1.   JSP视窗组件所使用的struts标签库由4类标签组成

Bean标记:在JSP页中管理beanstruts-bean.tld

逻辑标记:在JSP页中控制流程,struts-logic.tld

HTML标记:用来生成HTML标记,在表单中显示数据,使用会话IDURL进行编程,

struts-html.tld

tiles标记:使用动态模板构造普通格式的网页,struts-tiles.tld

2.   Struts标记的导入代码

<%@taglib uri="http://struts.apache.org/tags-bean"prefix="bean" %>

<%@taglib uri="http://struts.apache.org/tags-logic"prefix="logic" %>

<%@ taglib uri="http://struts.apache.org/tags-html"prefix="html" %>

<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>

 

3.   uriprefix属性

(1)   uri

如果没有背下来uri怎么写,那么可以将struts-taglib-1.3.10.jar包导入进myeclpse,然后查看其META-INF.tld目录下的标签文件信息,包含了4个文件:

Struts-bean.tld

Struts-html.tld

Struts-logic.tld

Struts-nested.tld

打开这几个文件,就可以各自的uri的信息,例如beanuri

<tlib-version>1.3</tlib-version>

    <jsp-version>1.2</jsp-version>

    <short-name>bean</short-name>

    <uri>http://struts.apache.org/tags-bean</uri>

(2)   prefix

要引用哪个标记,就写哪个标记的名称

 

 

-------------------------------bean标记------------------------------

1.   definewrite

JSP页面中

先定义

<%

       String username="Shiki";

       request.setAttribute("username",username);   

%>

body

<bean:define id="username1" name="username" scope="request"toScope="session"></bean:define>

标签获取username:<bean:write name="username1"/><br>

表达式获取username:${username1}

 

定义一个username字符串,值为”Shiki”,放入了request中,名称为username

username1代替了username的值,然后用标记和表达式分别输出

这段代表表示,define从已有的变量或者变量的属性定义一个新的变量,write用于输出该属性到JspWriter

definescope属性定义获取值时的属性范围,而toScope属性定义输出值时的属性范围

2.   message

配合ApplicationResources.properties资源文件来实现Struts的国际化功能

(1)  定义资源文件

相应语言的资源文件的名字

英语:ApplicationResources_en_US.properties

中文:ApplicationResources_zh_CN.properties

一定要注意语言的后缀,en_USzh_CN,如果想用IE浏览器的语言切换来查看,就必须使用这些后缀名,名字不能改变

配置文件的格式为:

配置英文

Welcome=welcome

配置中文时,需要将中文转换成为Unicode编码,资源文件才可以通过转换而识别中文

Welcome= /u6b22/u8fce(中文的欢迎”)

资源文件的格式都是以键值对的形式来填写的

(2)  修改struts-config.xml配置文件

<message-resources parameter="com.user.struts.ApplicationResources"key="MyKey"/>

(3)  JSP页面中使用<bean:message>标记

Struts实现国际化:<br>

<bean:message bundle="MyKey"key="language"/>语言:

<bean:message bundle="MyKey"key="welcome"/>

(4)  使用IE来查看网页文字国际化的效果

打开IE—工具—Internet选项常规语言,选择某一种当前浏览器使用的语言

Struts会找到相应语言后缀的资源文件的某个键并获取相应的值

 

 

-------------------------------logic标记-----------------------------

logic提供了一组在JSP页中处理流程控制的标记,这些标记封装在文件名为struts-logic.tld的标记包中。

该标记的主要三个功能是:条件逻辑,重复,转发/重定向响应

1.   iterate

用于在对象集合中循环从而重复的产生输出文本,以及应用程序流程控制。

JSP页面中

先定义

<%

    String[] usernames={"黑桐干也","两仪式","苍崎橙子"};

    request.setAttribute("user",usernames);  

%>

body

Struts实现iterator迭代器的功能:

<logic:iterate id="user" name="user"scope="request" indexId="id">

${id}&nbsp;<bean:write name="user"/>&nbsp;&nbsp;

</logic:iterate> Iterate标记的scope属性定义了获取值时的属性范围,name属性用于接收相应属性范围传递过来的值,id是该iterate标记定义一个新的对象,indexId可以为循环中的每个值指定一个编号,表达式${id}可以用来输出该编号

当要使用bean:write标记来输出时,将使用id所定义的值的名称

logic:iterate标记中也可以再次嵌套logic:iterate标记,实现双重循环

2.   notPresentpresent

在一张页面可以充当两张页面,登录成功如何,不成功如何,都在一页中显示

例如我要判断我前台页面的name属性是否等于”Shiki”

(1)   Action

if(name.equals("Shiki")){

           HttpSession session=request.getSession();

           session.setAttribute("user", name);

}

如果name等于”Shiki”,就把”Shiki”保存在session范围中

(2)   jsp页面中

    <logic:notPresent name="user" scope="session">

        该用户不存在!

    </logic:notPresent>

    <logic:present name="user" scope="session">

        ${user}  登录成功

 </logic:present>

Scope属性当前将值保存在哪个作用域范围中,Name属性表示传递过来的值

logic:notPresent当前页面的作用域范围内的值不存在时,显示什么

logic:present当该值存在时,显示什么

 

 

-------------------------------动态Form-----------------------------

1.   Dynamic FormBean 动态Form,没有具体的物理文件,是在struts-config.xml文件中配置的

2.   配置动态Form格式:

<form-bean name="userDynaForm" type="org.apache.struts.action.DynaActionForm">

<form-property name="password"type="java.lang.String" />

<form-property name="name"type="java.lang.String" />

<form-property name="id"type="java.lang.String" />

</form-bean>

3.   配置Action

<action

      attribute="userDynaForm"

      name="userDynaForm"

      path="/userDyna"

      scope="request"

      type="com.user.Action.UserDynaAction"/>

 

4.   通过在JSP或静态页面的表单中输入数据,然后跳转到指定了userDynaFormAction

这样所有的数据就会放入动态Form

JSP页面:

<form action="userDyna.do" method="post">

    password&nbsp;<input type="text" name="password"> <br>

    name&nbsp;<input type="text" name="name"> <br>

    id&nbsp;<input type="text" name="id"> <br>

    <input type="submit"value="提交">

    <input type="reset"value="取消"> <br>

</form>

如果是用普通的html语法,action就要写成.do的形式

如果是采用strutshtml标签语法,action就不需要写后缀名.do的形式

Action页面:

DynaActionForm DynaForm =(DynaActionForm) form;

PrintWriter out=response.getWriter();

out.print("This is userDyna");

String name=(String)DynaForm.get("name");

String password=(String)DynaForm.get("password");

String id=(String)DynaForm.get("id");

out.print("<br>"+id+" "+name+" "+password);

return null;

普通的formbeanAction获取表单中的值时,是使用setget方法,而动态Form则在Action中使用get(“属性名”)的方式来取值

5.   使用普通的FormBean时,在Action的跳转页面上查看用户注册的信息,可以使用表达式${formbean.properties}

而使用动态Form时,想查看注册信息的表达式格式为${dynaform.map.properties}

普通的FormBean是使用set方法来保存,而动态Form是使用map集合来保存的

 

 

----------------------------Struts的异常处理-------------------------

1.   创建一个Exception类的子类,在构造方法中调用父类的构造方法,并传递一个错误信息

public class MyException extends Exception {

    public MyException(String message){

       super(message);

    }

2.   }配置struts-config.xml文件

<exception path="/errors.jsp"key="error" type="com.exception.MyException"></exception>

(1)   Path出现异常后的跳转页面

(2)   用资源文件来存放异常信息,以键值对的形式,key是异常信息的键,通过key可以从   资源文件中获取到值,所以也要在struts-config.xml中配置资源文件

<message-resources parameter="com.user.struts.ApplicationResources"/>

message-resources标记不能包含key属性,所以如果想与国际化功能同时实现,就要配置两个资源文件,一个带key,一个不带key

<message-resources parameter="com.user.struts.ApplicationResources"key="language"/>

<message-resources parameter="com.user.struts.ApplicationResources"/>

(3)   Type是所要处理的异常,一般是自己定义一个Exception的子类

3.   在相应的Action中的execute方法中抛出异常

if(name.equals("java")){

throw new MyException("invalid");

}

4.   在异常处理页面(path所指定的页面)使用struts标记<html:errors>来输出资源文件中所包含的异常信息,该信息是由配置文件中exception标记的key属性来决定的

This is Exception page. <br>

<html:errors/>

 

------------------------ForwardAction 全局跳转------------------------

1.   将所有的*.jsp访问形式改变成统一访问模式*.do

2.   所有的jspWEB-INF

3.   所有jsp的请求之前需要先访问Action

struts-config.xml配置文件中设置Action

<action path="/fowardAction"forward="/user.jsp"></action>    

4.jsp将由定义的Action—forwardAction.do来访问

 

 

-----------------------------DispatchAction--------------------------

加入我要实现一个模块,需要对学生信息进行CURD操作

遵照StrutsMVC设计模式,Action作为控制器来使用

有以下4Action

AddStudentActionDeleteStudentActionUpdateStudentActioQueryStudentAction

每个CURD操作就要对应一个Action,然后调用DAO方法来实现该功能,并作出跳转

但这样的缺点是:Action过多,所以需要合并相关的Action来简化操作

所以我们需要使用DispatchAction来实现带参数的一个Action包含多个可执行方法,多个提交组件针对一个Action,感觉像是同时包含个了多个Action,却实际减少了Action的数量,

1. 创建一个DispatchAction的子类,这里的方法必须与原来的execute方法同参数同返回值,但可以自定义方法名称,以此同时来包含多个这样的方法,实现多个Action

但是Action中的方法名称可以有多种,但是决不能是execute

2. 修改struts-config.xml配置

<action path="/studentAction"type="com.user.Action.StudentActionAction"parameter="operationType"/>

 

<html:link action="studentAction?operationType=AddStudentAction">

    添加学生

</html:link>

根据parameter="operationType"参数所定义的内容去匹配Action中的方法名,分别调用不同的方法

 

 

------------------------------预处理类--------------------------------

实现对struts中各个网页的文字编码过滤转换

1.   创建com.en包,创建一个Encoding类,该类继承于RequestProcessor类,是一个预处理类,对struts里边所有的请求提前作出预处理

public class Encoding extends RequestProcessor {}

2.   覆盖父类方法processPreprocess

protected boolean processPreprocess(HttpServletRequest req,HttpServletResponse resp) {

       req.setCharacterEncoding("gbk");

       return true;

}

这个方法整合了过滤器和监听器,requestresponse都可以实现过滤功能

3.   修改struts-config.xml配置文件

</struts-config>中作为单独的一个元素来配置

<controller processorClass="com.en.Encoding"></controller>