struts1学习笔记--工作原理

来源:互联网 发布:程序员盗600万 编辑:程序博客网 时间:2024/05/02 00:24

一、引入struts
Model 1结构如图1所示:


    Mode1 1是一个以JSP文件为中心的模式,在这种模式中JSP页面不仅负责表现逻辑,也负责控制逻辑。专业书籍上称之为逻辑耦合在页面中,这种处理方式,对一些规模很小的项目如:一个简单的留言簿,也没什么太大的坏处,实际上,人们开始接触一些对自己来说是新的东西的时候,比如,用JSP访问数据库时,往往喜欢别人能提供一个包含这一切的单个JSP页面,因为这样在一个页面上他就可以把握全局,便于理解。但是,用Model 1模式开发大型时,程序流向由一些互相能够感知的页面决定,当页面很多时要清楚地把握其流向将是很复杂的事情,当您修改一页时可能会影响相关的很多页面,大有牵一发而动全身的感觉,使得程序的修改与维护变得异常困难;还有一个问题就是程序逻辑开发与页面设计纠缠在一起,既不便于分工合作也不利于代码的重用,这样的程序其健壮性和可伸缩性都不好。

Model 2引入了"控制器"这个概念,控制器一般由Servlet来担任,客户端的请求不再直接送给一个处理业务逻辑的JSP页面,而是送给这个控制器,再由控制器根据具体的请求调用不同的事务逻辑,并将处理结果返回到合适的页面。因此,这个servlet控制器为应用程序提供了一个进行前-后端处理的中枢。一方面为输入数据的验证、身份认证、日志及实现国际化编程提供了一个合适的切入点;另一方面也提供了将业务逻辑从JSP文件剥离的可能。业务逻辑从JSP页面分离后,JSP文件蜕变成一个单纯完成显示任务的东西,这就是常说的View。而独立出来的事务逻辑变成人们常说的Model,再加上控制器Control本身,就构成了MVC模式。实践证明,MVC模式为大型程序的开发及维护提供了巨大的便利。

二、struts工作原理
 
来自客户的所有需要通过框架的请求,统一由ActionServlet接收(ActionServlet Struts已经为我们写好了,只要您应用没有什么特别的要求,它基本上都能满足您的要求),根据接收的请求参数和Struts配置(struts-config.XML)中ActionMapping,将请求送给合适的Action去处理,解决由谁做的问题,它们共同构成Struts的控制器。
Action则是Struts应用中真正干活的组件,它解决的是做什么的问题,它通过调用需要的业务组件(模型)来完成应用的业务,业务组件解决的是如何做的问题,并将执行的结果返回一个代表所需的描绘响应的JSP(或Action)的ActionForward对象给ActionServlet以将响应呈现给客户。
这里要特别说明一下的是:就是Action这个类,它不应该包含过多的业务逻辑,而应该只是简单地收集业务方法所需要的数据并传递给业务对象。实际上,它的主要职责是:
校验前提条件或者声明 调用需要的业务逻辑方法 检测或处理其他错误 路由控制到相关视图

三、struts运行机制 Struts的工作流程: 

在web应用启动时就会加载,初始化ActionServlet,ActionServlet从struts-config.xml文件中读取配置信息,把它们存放到各种配置对象中,当ActionServlet接收到一个客户请求时,将执行如下流程.  
(1)检索和用户请求匹配的ActionMapping实例,如果不存在就返回请求路径无效信息;

(2)如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中; 
(3)根据配置信息决定是否需要表单验证.如果需要验证,就调用ActionForm的validate()方法; 
(4)如果ActionForm的validate()方法返回null或返回一个不包含ActionMessage的ActuibErrors对象, 就表示表单验证成功; 
(5)ActionServlet根据ActionMapping所包含的映射信息决定将请求转发给哪个Action,如果相应的Action实例不存在,就先创建这个实例,然后调用Action的execute()方法; 
(6)Action的execute()方法返回一个ActionForward对象,ActionServlet在把客户请求转发给 ActionForward对象指向的JSP组件; 
(7)ActionForward对象指向JSP组件生成动态网页,返回给客户; 

特别说明:

ActionMapping类

        ActionMapping的一个实例对应了struts-config.xml文件中的一个<action>标签。其比较重要的几个属性有path,type,name,scope,input,forward,unknown等。

         path为其访问路径,type是action类型,name为ActionForm的name,scope是将信息设置到request或者session中。这些都比较简单。重点说一下forward和input属性。

         forward属性,Action为逻辑控制器,如果我们有转向信息而没有逻辑代码时,我们一般的做法是建立一个Action,里面只写一句转向信息的代码,如果有很多这样的Action,那么操作将非常繁琐,这时可以利用forward属性来配置其转向信息,而不用建立一个action类。使用forward属性有利于体现配置文件的完整性,应尽量使用。

         unknown属性,这个是一个缺省配置,当输入的url找不到时,会跳转到unknown页面,unknown属性设置是一个页面的路径。

         input属性,这个属性和异常有关系,当出现错误时,我们原来是跳转到错误页面,用input可以实现同样的效果。看代码。

  1. <action path="/login_struts_tag"   
  2. type="com.bjpowernode.struts.LoginAction"  
  3. name="loginForm"                  
  4. scope="request"          
  5. input="/login_struts_tag.jsp"          
  6. >  
  7. <forward name="success" path="/login_success.jsp" />  
  8. <!--  
  9. <forward name="error" path="/login_error.jsp"/> 
  10.  -->                  
  11. </action>  

         在Action中代码则改变为Return mapping.getInputForward();,和原来return mapping.findForward("error");效果一样。


DispatchAction类

         DispatchAction类继承自Action类,是一种特殊的Action类。在用Action的时候,有的时候会创建很多的Action类,这时候可以用DispatchAction类来将不同的Action类化成不同的方法。即用一个DispatchAction类可以完成多个方法。

         在用这个类的时候,首先要在struts-config.xml文件中的action标签多写一个parameter属性,因为在界面写访问路径的时候要带有参数,才能在DispatchAction中判断调用什么方法。配置代码为

    <action path="/user/user_maint"

             type="com.bjpowernode.drp.web.actions.UserAction"

             name="userForm"

             scope="request"

             parameter="command"

   parameter的含义为命令的关键字是什么,即在界面代码action ="user_maint.do?command=del";这个关键字可以替换。parameter中的值不能是execute和perform。

   在得到del后,在DispatchAction中写的方法名称必须和这个一样。才能调用到这个方法上。

   在DispatchAction中还有一个unspecified方法,即界面不传任何参数的时候调用到这个方法上。

    DispatchAction中的execute方法,如果需要覆盖,必须显示调用。

静态和动态actionform

         actionform是struts框架的核心类之一,其类似于一个实体类,收集并保存表单的上每个数据。它是struts解析了struts-config.xml文件创建出actionmapping类之后,根据actionmapping类中的name属性创建的。

         actionform一般为静态类,如果为静态类,那么使用方法和面向对象中的实体类相似。actionform也可以动态配置,即在struts-config.xml文件中灵活配置,实现动态功能。

         配置动态actionform时,和配置静态actionform类似,首先要有一个<form-beans>的标签,具体配置如下。

<form-beans>

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

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

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

</form-bean>

</form-beans>

         和配置静态类不一样的,就是其中多了属性配置,这个很容易理解。在配置文件配置完成后,struts会把配置的这些属性放到一个map中,这个map的value是其真正的值。

 

         在action类中取得actionform类的值,在静态的类,直接打出对象的名字即可取得配置到其中的值,在动态的actionform中,则不能直接取得,上面说过,struts会把这些值放到map中,所以可以通过map取得。具体用法如下

DynaActionForm daf = (DynaActionForm)form;

String username =(String)daf.get("username");

Integer age = (Integer)daf.get("age");

         因为他们无论form,还是DynaActionForm,都是继承与actionform,所以可以进行强制转换,强转完成后则直接可以从中get取值。

 

         在界面如何通过er表达式取得动态actionform的值:

         用户:${dynaForm.map.username }

         年龄:${dynaForm.map.age }

         还是利用map,在动态actionform的map中取得。

 

         动态actionform不建议使用,毕竟动态设置有利有弊,可以灵活的设置,但是如果设置的太多,容易弄乱,配置类型的时候可能把数据类型写错,在这里大致了解就好。

 

ActionForm之上传

采用struts上传和普通上传大同小异,界面的表单必须写enctype="multipart/form-data",如下面所示:

<form action="upload.do"method="post" enctype="multipart/form-data">

                 标题:<inputtype="text" name="title"><br>

                 文件:<inputtype="file" name="myfile"><br>

                 <inputtype="submit" value="提交">

         </form>

         ActionForm中使用FormFile来接收上传的文件,参见:UploadActionForm.java

         在Action中调用FormFile取得上传文件数据,采用流输出,即完成上传,参见:UploadTestAction.java

         采用<controller/>标签配置上传参数,如:<controllermaxFileSize="10M"/>


ActionForm中代码:

[java] view plaincopyprint?
  1. public class UploadActionForm extends ActionForm {  
  2.   
  3.     private String title;  
  4.       
  5.     //上传的文件必须采用FormFile声明  
  6.     private FormFile myfile;  
  7.   
  8.     public String getTitle() {  
  9.         return title;  
  10.     }  
  11.   
  12.     public void setTitle(String title) {  
  13.         this.title = title;  
  14.     }  
  15.   
  16.     public FormFile getMyfile() {  
  17.         return myfile;  
  18.     }  
  19.   
  20.     public void setMyfile(FormFile myfile) {  
  21.         this.myfile = myfile;  
  22.     }  
  23. }  


Action中代码

[java] view plaincopyprint?
  1. public class UploadTestAction extends Action {  
  2.     public ActionForward execute(ActionMapping mapping, ActionForm form,  
  3.             HttpServletRequest request, HttpServletResponse response)  
  4.             throws Exception {  
  5.         UploadActionForm uaf = (UploadActionForm)form;  
  6.         System.out.println("title=" + uaf.getTitle());  
  7.         System.out.println("fileName=" + uaf.getMyfile().getFileName());  
  8.         //采用输出流输出到d盘根目录  
  9.         FileOutputStream fos = new FileOutputStream("d:\\" + uaf.getMyfile().getFileName());  
  10.         fos.write(uaf.getMyfile().getFileData());  
  11.         fos.flush();  
  12.         fos.close();  
  13.         return mapping.findForward("success");  
  14.     }  
  15. }  

ActionForward类

         actionforward类是在action的一个处理结果,action的execute处理结果返回对象为一个actionforward。这个类一般都包含转发或者重定向信息。在struts-config.xml文件中配置forward标签时,只有四个属性,name,path,redirect,classname。

         actionForward的redirect属性

         当redirect=false时,将保存存储在http请求和请求上下文中的所有内容,仅在同一个应用中可用。当redirect=true时,Web客户端进行一次新的http请求,请求的资源可以在同一个应用中,也可以不在,原来的请求参数不再保存,原来的请求上下文也被清除,新的http请求仅包含ActionForward的path属性里所包含的参数。即redirect=true时为重定向,redirect=false时,为转发。

         ActionForward全局与局部的概念

         在配置action时,如果有很多的action配置都需要转向同样的页面,那么在每个action里面都需要重新配置一遍,这样代码重复太多,所以ActionForward有全局和局部的概念。

         每个action都配置一个forward时,这就是局部ActionForward,如果有很多的action都需要同一个ActionForward。那么就可以配置全局的ActionForward。配置方法为,和Action-mapping标签平级。使用<global-forward></global-forward>标签。

   <global-forwards>

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

   </global-forwards>

   注意这个一定要配置在action-mapping外,如果同时配置了局部和全局的ActionForward,那么就近原则,先找局部的,如果局部的没有找到,则在找全局变量。

 

         将受保护的页面放到WEB-INF下

         有一些受保护的页面通过url可以直接访问,我们可以把它放到WEB-INF文件夹下,这个文件夹下的文件都是受保护的。通过url不可以直接访问。

         但是如果放到了这个文件夹下,在配置forward标签的时候path属性要加上相应的路径,因为forward标签默认是从WebRoot根目录下寻找。

 

         手动转向

         有的时候在用struts开发时,我们不需要ActionForward来帮我们进行转向,这时execute方法直接返回null就可以,返回null就表示不用ActionForward来进行转向。这时候可以用response.sendRediect来自己进行转向。

         如果不是必须手动转向,一般建议要用struts进行转向,因为struts是配置,灵活,而且通过配置文件就知道要转向到哪里,这些都是struts的优点。

 

         动态ActionForward

         在有的时候,一个action可能要转向很多个页面,这时候需要在配置文件中进行多个配置。但是这时候我们不希望修改Action中的代码,这时候就需要动态ActionForward了。

         动态ActionForward不是有专门的配置,而是在Action中利用ActionForward的setPath方法,来动态的设置转向路径,从而实现动态效果。下面是一个实例。

[java] view plaincopyprint?
  1. <span style="font-size: 18px;">
  2.  public ActionForward execute(ActionMapping mapping, ActionForm form,  
  3.             HttpServletRequest request, HttpServletResponse response)  
  4.             throws Exception {  
  5.         //从界面取得要转向的页面号  
  6.         int page = Integer.parseInt(request.getParameter("page"));  
  7.         ActionForward myAf = new ActionForward();  
  8.         //设置要转向的页面号,因为是从页面获取的,页面可以随意输入,即动态  
  9.         af.setPath("/page" + page + ".jsp");  
  10.         return af;  
  11.     }  
  12. </span>  


0 0