Struts

 Struts实用开发指南--高红岩

 

<1>ActionServlet执行流程:

调用RequestUtils的selectApplication取得请求路径(URI)

委托RequestProcesssor处理请求

 

<2>RequestProcessor的process()主要执行流程:

A。从URI路径确定ActionMapping,ActionServlet用ActionMapping得知所使用的Action(从path属性)

B。创建ActionForm,将浏览器字段填入

C。判断是否执行ActionForm的validate()方法,若执行,还要根据其结果跳转

D。创建Action,执行其execute()方法,并返回ActionForward

E。处理ActionForward

 

<3>在Struts中,一个Action类在ActionMapping中只对应一个实例对象,由ActionServlet创建后,

之后一直使用它(有点单例的味道)

 

<4>Action本质上也是Servlet(处理流程),而不应该在Action中加入过多逻辑,Action对象也属于控制角色,

与业务相关的工作由辅助类来实现。

 

<5>ActionErrors可以含有多个ActionError,如

errors.add("username",new ActionError("username_wrong");

                      |对应                                               |对应

 <html:errors property="username"/>     资源文件:username_wrong=your nme wrong!

 

<6>ActionForm不用时可以去掉:

如,request.removeAttribute(mapping.getName());

或,request.getSession().removeAttribute(mapping.getName());

 

<7>ActionForward的两种创建方法:

A。在Struts-config.xml中

B。在程序中,如在execute()中用    ActionForward a=new ActiongForward();

     (不推荐,不具共享)                     a.setName(“abd ”);

                                                                  a.setPath(“/form/a.jsp”);

C。带参数形式:new ActionForward(path+“&abc=133”,true);

 

<8>标准内置Action类:

A。ForwardAction与超级链接功能相同,不必提交到Action,可直接提交到jsp文件

好处:通过控制器

            不会暴露目标地址

 

B。IncludeAction让非StrutsMVC应用的组件得到重用,它是动态的,可以传递参数

 

A与B都有相似的功能--换页面

不同:B不只“换地址”还有提交数据的功能(传递参数)

 

C。继承DispatchAction使在一个Action中完成多个类似的业务逻辑如,增,删,改。通过在页面中定义一个隐藏变量,

DispatchAction已经实现父类Action的execute(),所以继承它的子类不必再实现该方法,而关注于具体业务,如上面的

增,删,改。

 

D。lookupDispathAction实现一个表单包含多个提交按钮

与DispaAction不同的是它用资源文件中的key作为请求参数来进行对方法的映射,而DispathAction是通过请求参数来选择方法

 

E。SwitchAction实现切换到不同的Struts模块

 

<9>声明了一个ActionForm,在调用Action类的方法之前的流程:

A。检查这个Bean在一定范围内是不是有一个实例。

B。如果没有,那么在一定范围内(request or session)生成该实例

C。调用该ActionForm实例的reset()方法

D。对于request的参数,如果和Bean中的属性相匹配,那么该Bean的实例调用setter()(即把表单的数据填入ActionForm)

E。调用该ActionForm的validat()方法

F。修改的ActionForm会被Action获得,在Action中执行业务逻辑代码(execute())

 

<10>用DynaActionForm存在如下缺点:

A。数据验证:要用到validator框架,配置麻烦

B。与Action的耦合也存在,如在Action中用“String userID=(String)form。get(“userID”),当修改Form中的属性时候就必须

修改Action类,这与普通的ActionF的做法是一样的,失去了可配置的优势所在。

总结:推荐使用普通的ActionForm去履行DTO的职责。

 

<11>ActionForm中文乱码问题解决方案

A。Action类中解决办法(在execute()中)

如:ActionFrom cat=(ActionForm)from;

String name=new String(cat.getName()。getByte(“ISO-9959-1"),”UTF-8");

cat.setName(name);

 

B。ActionForm类中的解决办法

在ActionForm的reset()方法中加入如下代码

try

{

   httpServletRequest.setCharacterEncoding("GBK");

}

catch(UnsupportedEncodingException ex)

{

}

总结:相对以上两种方法推荐使用第二中,但是在处理中文问题,为达到国际化,最好还是用监听器并在web.xml中配置。

 

<12>一些Struts标签:

A。<html:cancel>

生成一个取消按钮,当单击该按钮后ActionServlet会绕过相应的Form Bean的validate()方法,同时将控制权交给相应的Action。

在该Action中可以使用Action.isCancelled(HttpServletRequest)方法判断是否被取消了,如果返回true表示这个Action被取消了,否则这个Action没被取消。

 

B。<html:errors>

a。局部错误信息:

<html:errors property="username"/>----->ActionErrors errors=new ActionErrors();

                                                                    errors.add("username",new ActionError("showWrong")

                                                           ----->资源文件:showWrong=username is wrong!

b。全局错误信息:

<html:errors/>------>ActionErrors errors=new ActionErrors();

                                   errors.add(errors.GLOBAL_ERROR,new ActionError("showWrong")

                        ----->资源文件:showWrong=username is wrong!

 

Struts1.2中使用ActionMessages和ActionMessage来代替ActionErrors和ActionError

 

C。<html:messages>

ps:为了使用validate()方法,<action>中的validate属性必须设为true,并且input属性也是必要的,当validate()传回ActionErrors时,就会传送至input所指定的位置。

 

Struts1.1中Message与Error的区别:所谓Error指使用者的输入在完整性或格式上有误(在FormBean中),而Message是指输入数据基本上没有错误,但不能符合后续处理要求(逻辑)(在Action中)。

 

Action中execute()中:

ActionMessages messages=new ActionMessages();

messages。add(ActionMessages.GLOBAL_MESSAGE,new ActionMessage(“passwordwerong”));

 

在JSP页面中显示错误:

<html:messages>的message属性如果不设为true,会输出ActionErrors中所存储的错误(通常为ActionForm中的错误)

<html:messages>的message属性如果设为true,会输出ActionMessages中所存储的错误(通常为Action中的错误)

 

<13>没有登陆不能访问非inde.jsp的jsp文件,可以使用Servlet的过滤功能。p244

 

《精通Struts》

第一章:

***视图

通常把Struts框架中的ActionForm Bean也划分到视图模块中。

 

***控制器

对于小型简单应用,Action类本身也可以完成一些实际的业务逻辑;对于大型应用,Action充当用户请求和业务逻辑之间的适配器(Adapor),其功能就是将请求也业务逻辑分开。

 

Action基类中excute()方法返回null,因此用户定义自己的Action类,即Action基类的子类时,必须覆盖execute()方法。

 

在内存中,每一个<action>元素都对应一个org.apache.struts.action.ActionMapping类的实例。

 

***模型

模型表示业务逻辑和业务数据

 

***Struts的工作流程

在web应用启动时就会加载并初始化ActionServlet,ActionServlet从struts-config.xml文件中读取配置信息,把它们存放到各种配置对象中,例如Action的映射信息存放在ActionMapping对象中。

 

检索和用户请求匹配的ActionMapping实例,如果不存在,就返回用户请求路径无效的信息。

 

如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中。

 

根据配置信息决定是否需要表单验证,如果需要,就调用ActionForm的validate()方法。

 

如果ActionForm的validate()方法返回null或返回一个不包含ActionMessage的ActionErrors对象,就表示表单验证成功。如果返回一个包含一个或多个ActionMessage的ActionErrors对象,就表示表单验证失败,此时ActionServlet将直接把请求转发给包含用户提交表单的JSP组件。

 

ActionServlet根据ActionMapping实例包含的映射信息决定将请求转发给哪个Action。如果相应的Action实例不存在,就先创建这个实例,然后调用Action的execute()方法。

 

Action的execute()方法返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指向的JSP组件。

 

ActionForward对象指向的JSP组件生成动态网页,返回给客户。

 

第二章:

***Struts框架中的ActionForm类是抽象的,必须在应用中创建它的子类。

 

***Action类中定义了getResources(HttpServletRequest request)方法,该方法返回当前默认的MessageResources对象,它封装了Resource Bundle中的文本内容,可以在execute()方法中访问资源文件中的内容如:

MessageResources messages=getResources(request);

String title=messages。getMessage(“hello.jsp.title”);

 

***视图组件中的文本内容保存在专门的消息资源文件中,在JSP文件中通过Struts的<bean:message>标签来访问它,这样可以很方便地实现Struts应用的国际化,支持多国语言。

 

***对于stuts应用,提倡将属性key常量定义在一个java文件Constants.java中。

 

***<html:form>标签在request范围中查找对应的ActionForm,如果存在这样的实例,就把ActionForm中的属性赋值给HTML表单对应属性文本框。

 

第三章:

***模型组件可以是JavaBean,EJB和使用类。

 

***Action负责当个事件的流程控制,如登陆,登出事件可以分别创建logonAction和logoffAction。

 

***客户化标签负责视图层的程序逻辑,如数据显示,或者进行会话的有效验证。客户化标签可以访问模型组件,也可以访问存放在Web应用的request,session和application范围内的应用数据。

 

***模型组件不应该访问Servlet API和Struts API中的类。

 

第四章:

***目前Struts框架只允许在应用中配置一个ActionServlet

 

***web.xml中config参数是配置Struts的ActionServlet专有的,它用来设置Struts配置文件的相对路径

 

***Struts应用启动时,会把Struts配置文件中的配置信息读入到内存中,并把她们存放在config包中相关的JavaBean类的实例中。

 

***org.apache.struts.config包中的每一个类都和Struts配置文件中特定的配置元素对应,例如<action>元素和ActionMapping类对应,<forward>元素和ActionForward类对应,ControllerConfig和<controller>元素对应。

 

***如果有多个子应用,每个子应用都会有一个ModuleConfig对象。ModuleConfig和Struts配置文件的根元素<struts-config>对应。

 

***<action>元素的forward,include和type属性相互排斥,只能配置气质的一项。

 

***org.apache.struts.config.ConfigRuleSet类决定了Digester组件解析配置文件并创建配置对象的规则。

 

第五章:

***Struts控制器组件主要包括:

ActionServlet组件:充当Struts框架的中央控制器。

RequestProcessor组件:充当每个子应用模块的请求处理器。

Action组件:负责处理一项具体的业务。

Struts框架采用ActiongServlet和RequestProcessor组件进行集中控制,并采用Action组件来处理单项业务。

 

***Servlet容器在ActionServlet被加载后立即执行它的init()方法。init()流程如下:

调用initInternal(),初始化Struts框架的内在消息资源。

调用initOther(),从web.xml加载ActionServlet的初始化参数,如config

调用initServlet(),从web.xml文件中加载ActionServlet的URL映射信息。还会注册web.xml和Struts配置文件所使用的DTD

调用initModuleConfig(),加载并解析默认子应用模块的Struts配置文件;创建ModuleConfig对象,把它存储在ServeltContext中

调用initModuleMessageResources(),加载并解析默认子应用模块的Struts配置文件;创建MessageResources对象,把它存储在ServeltContext中

调用initModuleDataSource(),加载数据源。如果配置文件没有定义<data-source>元素,就忽略这一流程。

调用initModulePlugins(),加载默认子应用模块的所有插件

如果还包含其他子应用模块,重复流程4-7

 

***当ActionServlet实例接收到Http请求后,在doGet()或doPost()方法中都会调用process()方法来处理请求。process()中调用工具类ModuleUtils类的selectModule()选择处理请求的子应用模块,把子应用模块的ModuleConfig和MessageResources对象存储到request中。process()的第二步操作为获得RequestProcessor类的实例,然后调用RequestProcessor的process()方法来完成实际的预处理请求操作。

 

***Sruts框架只允许应用中存在一个ActionServlet类,但是可以存在多个客户化的RequestProcessor类,每个子应用模块都可以拥有单独的RequestProcessor类。

 

***RequestProcessor的process()流程如下:

调用processMultipart()方法,由请求的contentType是否以mutipart/form-data开头决定是否将标准的HttpServletRequest对象重新包装以方便处理multipart类型的HTTP请求。

调用processPath(),获得请求的URI的路径,用与选择合适的Action

调用processLocal(),当ControllerConfig对象的elocal属性为true,将读取用户请求中包含的Local信息,然后把Local实例保存在session范围中。

调用processContent(),读取ControllerConfig对象的contentType属性,调用response.setContentType(contentType)方法。

调用processNoCache()读取ControllerConfig对象的nocache属性,决定是否加入去除缓存的参数头。

调用processPreprocess()方法,不执行任何参做,子类可以覆盖该方法实现扩展。

调用processMapping(),寻找和用户请求URI匹配的ActionMapping。

调用processRoles(),先判断是否为Action配置了安全角色,若是,调用isUserInRole()

调用processActionForm(),先判断ActionMapping是否配置了ActionForm。若是,从ActionForm的存储范围内寻找该ActionForm实例,若不存在,就创建一个,接下来把它保存在合适的范围中保存时使用的属性key为ActionMapping的name属性

调用processPopulate()方法,先调用ActionForm的reset()方法,再把请求中的表单的数据组装到ActionForm中。

调用processValidate()方法,检查返回的ActionErrors中是否包含ActionMessage

调用processForward(),判断ActionMapping是否配置了forward属性(对应<action>的forward属性)。

调用processInclude(),判断ActionMapping是否配置了include属性(对应<action>的include属性)。

调用processActionCreate(),判断Action缓存中是否存在这个Action实例,若没,就创建一个,并保存到Action缓存中。

调用processActionPerform(),该方法调用Action实例的execute()方法。

调用processActionForward(),把execute()返回的ActionForward作为参数传给它,来进行请求转发或重定向。

 

***Action类是用户请求和业务逻辑之间的桥梁,每个Action既可以负责请求转发也可以充当一项业务代理。

 

***RequestProcessor类包含一个HashMap,作为存放所有Action实例的缓存,每个Action实例在缓存中存放的属性key为Action类名。RequestProcessor类的processActionCreate()方法中,创建Action实例的代码位于同步代码块中,以保证只有一个线程创建Action实例。

 

***Action类保证线程安全的重要原则是在Action类中仅仅使用局部变量,谨慎使用实例变量。

 

***Action类中提供了一系列和Token相关的方法,可以解决重复提交

 

***Struts中提供了一套通用的使用类:如RequestUtiles,TagUtils,ModuleUtils,Globals等p125.

 

第六章:

***在分析阶段,需要创建概念模型;在设计阶段,需要创建设计模型。

 

***概念模型描述了每个实例的概念和属性,以及实体之间的关系。但这个阶段并不描述实体的行为。

 

***设计模型可以用UML类框图,活动图以及状态图来描述。在设计模型中应该定义对象的方法。

 

***业务对象可以分为三种:

实体业务对象。

过程业务对象。

事件业务对象。

 

第七章:

***采用DTO来传输数据的好处:

减少传输数据的冗余,提高传输效率。

有助于实现各个层之间的独立,使得每个层分工明确。

 

***由于ActionForm类中使用了Servlet API,因此不提倡直接把ActionForm Bean传给模型层,而应在控制层把ActionForm Bean的数据重新组装到自定义的DTO中,再把它传递给模型层。

 

***ActionForm Bean有两种范围:request和session(默认)。

 

***当控制器接收到一个新的请求时,ActionForm的生命周期如下:

                                                                               控制器接收到请求

                                                                                               |

                      从request或session范围取出ActionForm实例,如果实例不存在,就自动创建一个新的实例。

                                                                                               |

                                                                    调用ActionForm的reset()方法

                                                                                                |

                                                        把ActionForm实例保存到request或session范围里

                                                                                                 |

                                                             把用户输入的表单数据组装到ActionForm中

                                                                                                 |

                                          如果<action>的validate属性为true,就调用ActionForm的validate方法

                                                                 |                                                             |

存在错误转发给<action.>的input属性指点的web组件      无验证错误调用Action的execute方法,把ActionForm的实例传Action       

ActionForm实例依然存在request或session范围内              的excute方法

                                                                                                                               |

                                                                                         把请求转发给其他web组件,ActionForm实例依然存在request或session范围内

 

第9章:

***java.util.ResourceBundle类提供存放和管理与Locale相关的资源的功能。这些资源包括文本域或按钮的Lable,状态信息,图片名,错误信息和页标题等。

 

***struts中没有直接使用ResourceBundle,而是使用MessageResources和它的子类PropertyMessageResources提供相似的功能。

 

***Struts应用的每个Resource Bundle和MessageResources(实际上是其子类PropertyMessageResources)的一个实例对应,MessageResources对象中存放了来自资源文件的文本。当应用初始化时,这些MessageResources实例被存储在ServletContext中,因此任何一个web组件都可以访问它们。

 

***Struts框架中的许多内在组件和Resource Bundle是绑定在一起的,如:

ActionMessage类

<html:errors>标签

<bean:message>标签

Validator验证框架中访问Resource Bundle

在声明异常处理中访问Resource Bundle

 

***采用Servlet过滤器设置请求数据的字符编码,因为它可以预处理所有的HTTP请求,这样能避免在每个web组件中设置请求数据编码。

 

***在同一个会话中,Struts框架仅读取HTTP请求的Locale信息一次,然后就把Locale对象保存在session范围内,因此在同一个会话中,Locale对象保持不变,选用的资源文件也不变。

 

***Struts应用的国际化应该遵守的原则:

尽量不在Servlet中使用非英文字符的常量字符串。

对于JSP文件,应该对page指令中的charset属性进行相应的设置。

不要在JSP文件中直接包含本地化的消息资源,而是把消息资源存放在Resource Bundle的资源文件中。

不必在每个JSP和Servlet中设置HTTP请求的字符编码,可以在Servlet过滤器中设置编码。

尽量使用UTF-8作为HTTP请求和响应的字符编码,而不是GBK或GB2312

充分考虑底层数据库所使用的编码。

 

第10章

***validator框架不能用于验证标准的ActionForm,如果使用validator框架,应该采用ActionForm的两个子类:DynaValidatorForm和ValidatorForm

 

第11章:

***java异常跟类为java.lang.Throwable,有两个直接的子类:java.lang.Error和java.lang.Exception。Error类表示程序本身无法恢复的严重错误,如java虚拟机错误。Exception类表示可以被程序捕获并处理的错误。在Struts应用中自定义的异常必须直接或间接继承Exception。

 

***JVM用方法调用栈来跟踪每个线程中一系列的方法调用过程。该栈中保存了每个调用方法的本地信息。

 

***JVM定位异常处理代码块需要做大量的工作。因此不应该使用异常处理机制来控制程序的正常流程,而应该确保仅仅在程序中可能出现异常的地方使用try/catch语句。此外,应该使用异常处理代码块位于适当的层次,如果当前方法具备处理可能发生的某种异常的能力,就尽量自行处理,不要把自己可以处理的异常推让给上层调用方法去处理。

 

***从开发应用的角度看,可以把异常分为系统异常和应用异常。

 

***在处理异常时,要注意不能让终端用户看到原始的java异常信息,应对原始的java异常进行包装,然后向用户显示容易理解的错误信息。

 

***当不需要用户来处理和关心原始的异常类时,最常见的做法是捕获原始的异常,把它包装成为一个新的不同类型的异常,再抛出新的异常,如:

try{}

catch(SQLException  e)

{throw new UploadException();}

 

***异常链(得到根异常)

try{}

catch(SQLException  e)

{UploadException ue=new UploadException();

  ue.setRootCause(e);

   throw new UploadException();}

 

***处理多样化异常:

BaseException be=new BaseExceptions();

try{   a();   }

catch(field2Exception  e)

{be.addException(e);}

try{   b();   }

catch(field2Exception  e)

{be.addException(e);}

throw be;

 

***Struts框架再视图层和控制层提供了对异常处理的支持。

 

***Struts的控制器负责捕获各种异常,包括控制器运行中本身抛出的异常,以及调用模型的业务方法时抛出的异常

 

***Struts框架异常处理机制流程:

ActionServlet的process()--->RequestProcessor的process()--->Action的execute()--->Model的业务方法

不捕获,抛出IOException         不捕获,抛出IOException  

或ServletException                       或ServletException,但------>该方法中调用的processActionPerform()中调用ActionPerform      

                                                                                                         的excute()并且调用processException()捕获异常。

                                                                                             -------> processException()中调用findException()(返回                                                                                                         ExceptionConfig 代表异常配置)        

                                                                                            ------->若找不到ExceptionConfig 就 向上层调用方法抛出异常,若找到就调                                                                                                         用getHandler()获得ExceptionHander,最后调用其execute()处理                                                                                                         异常();    ExceptionHander是Struts默认的异常处理类。

 

***在Struts中定义异常类:

a。扩展ModuleException。其优点是和Resource Bundle绑定。缺点是它是Struts控制层组件,不能被模型层使用。在Action类的excute()方法中,如果捕获了来自模型层的异常,要把它包装成ModuleException,才把它抛出。如

 try

{   

}

catch(bessinessException e)

{

       throw new SpecialModuleException();

} 尽管这两个异常类描述同一种错误,但不能违背MVC的分层原则,必须为它们分别编写程序代码。

b。创建自定义的异常类体系。为克服上面缺点,可以创建自己的异常类体系,模型层和控制层能够共同使用这些异常类。

 

***由java web容器捕获异常:

让web容器来捕获和业务逻辑相关的应用异常是不可取的,这种异常应该由Struts的控制器来处理,web容器通常负责捕获严重的系统错误。

 

***Struts框架支持两种异常处理方式:编程方式和配置方式

配置方式中可以使用Struts默认的ExceptionHander或创建自定义的ExceptionHander。

编程方式中通常在Action类中捕获异常。    

 

第16章:

***Titles框架是建立在JSP的include指令上的。                                                                           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值