湖北广播电视台:Struts入门(Struts 框架响应客户请求的流程+国际化+异常)
来源:百度文库 编辑:偶看新闻 时间:2024/04/28 00:39:50
Struts入门(Struts 框架响应客户请求的流程+国际化+异常)
JAVA 2007-07-15 12:41:15 阅读47 评论0 字号:大中小 订阅
Struts实际上是在JSPModel2上实现的一个MVC的框架。
模型:如JavaBean EJB
控制器:ActionServlet Action
视图:JSP Struts客户化标签
前端控制器:ActionServlet
控制器:Action
模型:ActionFormBean
控制器与模型之间的映射:ActionMapping
转发:ActionForward
错误与信息处理:ActionError
ActionForm Bean它也是一种JavaBean,除了一些JavaBean的常规方法,另外它还包含一些特殊的方法用于
验证其中数据的完整性。
Struts利用ActionFormBean来进行View组件与Controller组件之间表单数据的传递。
Struts框架把View组件接受的用户输入的表单数据保存在ActionForm bean之中,把它传递给Controller
组件,Controller组件可以对ActionForm Bean中的数据进行修改。
Jsp文件使用Struts标签读取修改后的ActionForm Bean的信息,重新设置HTML表单。
对于采用Struts的Web应用,在Web应用启动时会加载并初始化控制器ActionServlet。
ActionServlet从struts-config.xml配置文件中读取配置信息,再把它们存放到ActionMappings对象中。
ActionServlet在接收到用户请求时会检查对应的ActionMapping的实例是否存在,如果不存在则会创建一
个ActionMapping的实例,其中包含了把请求转发至那个Action的信息。
ActionServlet会根据配置文件检查Action对应的ActionForm的实例,如果ActionForm的实例不存在,则
会创建一个ActionForm的对象,并将客户提交的表单数据保存到ActionForm中。
ActionServlet在获取或建立ActionForm后,会根据配置是否需要验证来执行ActionForm的validate()方
法进行验证。
如果ActionForm的validate方法返回一个null或一个不包含ActionMessage的ActionErrors对象,就表示
表单验证成功。
ActionServlet根据配置来确定将请求转发给那个Action,如果相应的Action实例不存在,就会先创建这个
实例,然后调用它的execute方法。
Action的execute方法将返回一个ActionForward对象,ActionServlet再将请求转发给ActionForward中指
向的JSP组件。
然后ActionForward中指向的JSP组件生成动态网页返回给用户。
注:在执行ActionForm的validate方法进行数据验证时,如果验证失败(即:返回不为空,为一个
ActionError或ActionErrors对象时),此时ActionServlet会直接将请求转发给包客户提交表单的JSP组
件。这种情况下,将不再创建Action对象并调用它的execute方法。
在Struts各种组件中最重要的组件就是控制器组件.
Struts控制器组件的组成:
Struts控制器主要由ActionServlet组成,另外包含
RequestProcessor Action 及 ActionForward三个辅助类.
Struts多应用模块:
多应用模块是指同一个应用包含多个子应用,每个子应用可以处理相关的一组功能,例如:对于网上购物
,可以由一个子应用来处理商品和商品目录信息.再由另一个子应用来处理购物车和订单信息.
把应用划分为多个模块,可以简化应用的并行开发过程,缩短开发周期.
在Struts中,所有的子应用都共享同一个ServletAction但是每一个子应用都有单独的配置文件和
RequestProcesser实例.
Struts 框架的初始化流程:
Servlet容器会在ActionServlet被加载后立即执行它的init()方法,以下是ActionServlet的init的执行
过程分析:
调用initInternal()方法,初始化所有在Struts框架中用到的消息资源,例如:日志,警告,错误信息等
调用initOther()方法,从web.xml中加载ActionServlet的初始化参数,例如:config等.
调用initServlet()方法,从web.xml中加载ActionServlet的URL映射信息.
调用initModuleConfig()方法,加载并解析默认子应用模块的Struts配置文件,并创建ModuleConfig对象
,并且将它存储在ServletContext中.
调用initModuleMessageResource()方法,加载并初始化默认子应用模块的消息资源,并且建立
MessageResources对象,并将它保存在ServletContext中.
调用initModuleDataSource()方法,加载并实始化默认的子应用模块数据源,如果没有在struts的配置文
件中配置
调用initModulePlugins()方法,加载并初始化默认子应用模块的所有插件.
当默认的子应用模块初始化成功后,如果还有其它的子应用模块,ActionServlet将重复4到7的步骤,分
别对其它子模块进行初始化.
Struts 框架响应客户请求的流程:
当ActionServlet实例接收到HTTP请求后,在doGet()和doPost()方法中都会调用process()方法来处理请求.
ModuleUtils.getInstance().selectModule(request, getServletContext());//选择请求相关
的子应用模块
ModuleConfig config = getModuleConfig(request);//获取请求相关的配置文件
RequestProcessor processor = getProcessorForModule(config);//获取请求相关的处理器
if (processor == null) {
processor = getRequestProcessor(config);
}
processor.process(request, response);
RequestProcesser的process()方法:
首先调用processMultipart()方法.如果Http请求的为Post方法,并且请求的Content-type的类型为
mutipart/form-data,标准的HttpServletRequest将被重新封装以处理多数据体的Http请求,如果没有设
定Content-type则直接返回HttpServletRequest对象.
调用processPath()方法,获取请求的URI路径,该信息用于选择合适的Action组件
调用processLocale()方法,当ControllerConfig中的locale属性为true时,将读取用户请求中包含的
locale信息,然后把locale信息保存在session范围内.
调用processContent()方法,读取ControllerConfig中的contentType属性,然后调用
response.setContentType(contentType)的方法设置响应的文档类型及字符编码.
调用processNoCache()方法,通过读取ControllerConfig对象的nocache属性来设置是否在客户端的浏览
器中缓存页面.如果参数为true,那么将在响应的头信息中加入特定的头信息:Pragma, Cache-Control
和Expries.
调用processPreprocess()方法.该方法用于自定义的RequestProcesser重载,执行客户化的预处理请求
操作.返回true表示预处理成功.
调用processMapping()方法,在此寻找与用户请求相匹配的ActionMapping,如果不存在则返回出错信息
调用processRoles()方法,该方法先判断对应请求的Action是否配置了安全角色,如果配置了安全角色就
调用isUserInRole()方法来确定用户是否具备该角色,如果不具备将返回错误信息.
调用processActionForm()方法,该方法先判断是否为ActionMapping配置了ActionForm,如果配置了
ActionForm,就先从ActionForm的存在范围内查找该ActionForm的实例,如果不存在就创建一个新的实例
,接下来将它保存在合适的范围中,保存时的属性名称为ActionMapping中配置的name属性值.
调用processPopulate()方法.该方法检查ActionMapping是否配置了ActionForm,如果找到就调用
ActionForm的reset()方法,再把请求中的数据装载到ActionForm中.
调用processValidate()方法,如果ActionMapping配置了ActionForm,并且属性validate为true,此时将
调用ActionForm的validate()方法.如果validate()方法返回的ActionErrors对象中包含ActionMessage
对象,说明表单验证失败,此时将ActionErrors对象存储在request的范围中,再把请求发送给
ActionMapping的input属性指定的Web组件.如果ActionForm的validate()返回空则表示验证成功,就继
续执行下一步处理流程.
接下来调用processForward()方法,该方法判断是否在ActionMapping中配置了forward属性,如果配置了
这个属性就调用RequestDispatcher的forward()方法,执行转向,请求处理流程就结束了,否则进行下一
步操作.
调用processInclude()方法,该方法判断是否在ActionMapping中配置了include属性,如果配置了该属性
就调用RequestDispatcher的include()方法,请求处理流程就结束了,否则进行下一步操作.
调用processActionCreate(),该方法用于获取请求对应的Action,它先判断是否在Action缓存中存在这
个Action的实例,如果不存在,就建立一个并将它保存在缓存中.
调用processActionPerferm()方法,该方法调用Action的execute方法,execute方法位于try catch中,
以便捕获异常.
调用processActionForward()方法,把Action执行之后返回的ActionForward对象作为参数传给它,该方
法根据ActionForward指定的转发路径来执行转发或重定向操作.
Action类的execute方法:
execute方法的参数
ActionMapping :包含了该Action的配置信息,对应配置文件的action节点
ActionForm :包含了用户的表单数据,当Struts框架调用execute()方法时,
ActionForm中的数据已经通过了表单的验证.
HttpServletRequest:当前的Http请求对象
HttpServletResponse :当前的Http响应对象
该方法返回一ActionForward对象它包含了请求转发的路径信息.
定制Struts控制器组件:
定制Struts的ActionServlet,实际上只需要定制org.apache.struts.action.RequestProcessor 类即可
,该类真正包含了Struts在处理Servlet请求时所遵循的控制逻辑,该类的的process方法用来委托处理客
户请求,其中的定义一个预定义方法processPreprocess专门用于实现定制的控制逻辑.
在完成自定义的类后需要在对应模块的配置文件中加入
制类路径.
例:
什么是国际化?
国际化(简称I18N)是指在软件的设计阶段就应该使软件具有支持多种语言和地区的功能.这样当需要应
用中添加对一种新的语言和地区的支持时,不需要对已有的软件返工,无需修改应用的程序代码就能达到
修改的目的一种软件设计方法.
国际化的特征:
当应用需要支持一种新语言时,无需修改应用代码.
文本,消息,图片从源程序中抽取出来,存储在外.
根据用户的语言及地理位置,对与特定文化相关的数据,如日期,时间,货币进行正确的格式化.
可以方便的对应用做出相应的调整,使它适应的新的语言和地区.
Java中对I18N支持类:
Java.util.locale类
locale对象本身不执行格式化及国际化的解析工作,它只是负责传递有关用户的本地信息,这些
信息包括用户的语言,地理位置,操作系统等.
其中的getDefaultLocale()静态方法,可获取缺省的系统本地信息,此信息由JVM初始化.
Web系统的用户本地信息通过request请求对象可获取,通过request.getLocale();可获取请求用
户的本地信息.
Java.util.ResourceBundle类;
在Struts应用中访问Locale对象:
在配置Struts的Cottroller(ActionServlet)时,可以通过设定locale属性来设置是否将用户请求的
locale信息置于session中,缺省的为true,也就是根据用户的请求来却定用户的locale信息.
processLocale()方法把locale信息放入session中会检查,如果session中已存在或locale属性的设置不
为true都不会将locale信息置于session中.在自定义的Action中访问locale对象,Action的基类有提供
getLocale的方法用于获取locale对象.
该方法获取locale的过程为:
首先获取session作用域中的locale对象.
如果session中不存在,再通过HttpServletRequest的getLocale()获取locale对象。
ResourceBundle类:
Java.util.ResourceBundle类提供存放和管理和locale相关的资源的功能。这些资源包括文本提示,消息
,以及图片名,错误信息,网页标题之类的信息。
Struts框架并没有直接使用java框架下的ResourceBundle类,在Struts框架下主要存在两个类 :
org.apache.struts.util.MessageResources
org.apache.struts.util.PropertyMessageResources
这两个类都具有ResourceBundle的功能,其中PropertyMessageResources是MessageResources的
子类。
创建Struts的ResourceBundle:
Struts配置文件中的每个
Resource Bundle时它们通过key属性值来区分.
如果对应的key属性为空,表示为缺省的Resource Bundle.
例:
parameter指定资源包名称.
null:指定当查找的信息代码不存在时是否终止JSP处理,缺省为true
此处定义一个缺省的Resource Bundle,引用资源文件的基名为:appsource
当Struts处理Locale为中文的请求时,它会依次寻找如下资源文件:
application_zh_CN.properties
application_zh.properties
application.properties
Struts加载Resource Bundle:
Struts在启动时将每一个Resource Bundle进行加载并且将这些信息存储在一个
org.apache.struts.util.MessageResources类的实例中(实际上是PropertyMessageResources实例),这个
实例存储在ServletContext中,因此任何的Web组件都可以访问到它。
如何访问Resource Bundle?
1、通过编程来访问Resource Bundle
类似于Java I18N的ResourceBundle类的方法。
如下例:
public ActionForward execute(
ActionMapping map,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){
//获取用户请求的本地信息
Locale locale = this.getLocale(request);
//获取资源配置
MessageResources mr = this.getResources(request);
//根据用户的本地信息,获取资源中的信息
String msg = mr.getMessage(locale, “hello.i18n.str”);
…
}
2、使用和Resource Bundle绑定的Struts组件
Struts中许多内在的组件都是和Resource Bundle是邦定在一起的,例如:
ActionMessage类
在声明异常处理中使用Resource Bundle
联合使用ActionMessage类和
例如在验证用户登录时,如果用户登录不成功提示用户出错的原因,如下:
public ActionForward execute(
ActionMapping map,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){
ActionErrors errors = new ActionErrors(); //创建一个错误信息集合对象
LoginForm lf = (LoginForm)form;
LoginService ser = ServiceFac.getLoginService(); //验证用户登录
String userid = ser.checkLogin(form.getUser(), form.getPwd());
if(userid != null){//用户登录失败产生错误信息
errors.add(“login”, new ActionMessage(“login.error”));
}
saveErrors(request, errors);//存储错误信息到请求作用域中
…
}
在JSP页面中可通过
例如:
使用Bean标签库的
例如使用
在上面的示例中,该标签处理程序首先从session中获取用户的本地信息locale对象,然后从默认的
Resource Bundle中检索与locale对应的资源文件,再从资源文件中读取键值为app.title的字符串,最后
将获取的字符串输出。
bundle:需要指定特定的Resource Bundle时使用,对应配置文件中的Resource的key值。
如果不设置采用的就是缺省的Resource Bundle.
key:指定获取在Resource Bundle中的消息key。
对Struts应用进行国际化:
为了保证在同一JSP页面中能支持多种语言,可以将所有的JSP页面的字符编码方式统一设置为”UTF-8”
<%@page contentType=“text/html; charset=UTF-8” %>
UTF-8:是一种跨平台的字符编码。
注意:当页面设置为UTF-8的字符编码后,最好将页面进行转码(使用jdk中的native2ascii进行
转码)保存,另外页面所引用的文件如javascript,css,html,jsp文件均需要采用UTF-8编码,如果其中包
含非UTF-8字符(如汉字)需要转码保存。
对文本的国际化:
在JSP页面中不应当直接包含本地化的消息文本,而应当通过
得文本。
例:
对按钮的国际化:
可通过
对图片的国际化:
未使用国际化的图片
为了使JSP页面能根据不同的locale信息加载不同的图片,可如下设置:
altKey=“app.top.image.title”/> 创建资源文件: 创建默认的资源文件,默认的资源文件是不带任何的本地信息的properties文件,例如: application.properties。 建立与特定的locale相关的资源文件,是在默认的资源文件后加语言信息和地区信息,语言信息和本地信 息必需符合ISO命名规范。 例如: application_zh.properties application_zh_CN.properties 注意:如果建立的是中文资源文件需要使用JDK的native2ascii工具进行转码保存。 Java异常的处理方法: 在当前方法中通过try/catch语句捕获并处理异常,例如: try{ if(num < 0)throw new Exception(“error”); }catch(Exception e){ //处理异常 } 在方法的声明处通过throws语句,声明抛出异常,例如: public void methodA()throws Exception{ if(num < 0)throw new Exception(“error”); } 异常处理对性能的影响: 一般在Java程序中使用try/catch语句不会对应的性能造成太大的影响。仅当异常发生时,JVM需要执行额 外的操作,来定位异常处理的代码,这时会对性能产生负面异常。 如果抛出异常的代码块和捕获异常的代码块位于同一方法中,这种影响会小一些;但如果JVM必需搜索方 法调用堆栈来寻找异常处理代码块,其对性能的影响将比较大。 优化异常处理性能: 不应当使用异常处理机制来控制流程的正常流转,而应当确保仅仅在程序可能出现异常的地方使用 try/catch语句。 应该使异常处理代码块位于适当的层次,如果当前方法具备处理可能发生异常的能力,就尽量自行处理, 不要把自已可以处理的异常推让给上层调用方法。 Struts异常处理流程: Struts的前端控制器负责捕获和处理各种异常。 当Action调用业务对象发生异常时,异常将向上传递至ActionServlet,当ActionServlet捕获异常后,在 异常处理代码块中,它会建立描述异常信息的ActionMessage对象,并且将它保存在ActionMessages(或 ActionErrors)对象中,然后将ActionMessages保存在特定的作用域范围之内。 接下来,在视图层 地化的错误信息显示在网页上。 Struts异常处理的优点: 避免直接向用户显示原始的Java异常信息,而是在控制层对Java异常进行重新包装,在视图层提供能让用 户理解的错误信息。 Struts中向用户显示的错误信息来自于Resource Bundle,这有助于我们实现异常处理的国际化。 在Struts应用中处理异常的方式: 创建扩展的ModuleException类的异常类 以配置方式处理异常,通过配置 创建扩展的ModuleException异常类: 在Struts的API中提供了一个专门的异常类org.apache.struts.util.ModuleException,它是Exception的 子类,它在优点是可以很好的与Resouce Bundle进行邦定,因此可以支持异常国际化。 常用构造方法: ModuleException(java.lang.String key) ModuleException(java.lang.String key, java.lang.Object[] values) 其中的key指定错误消息的key,它与Resource Bundle中的key相匹配,values为错误消息的参数 。 (更多构造方法可以参考StrutsJavaDoc文档) 示例在Action中抛出ModuleException: public ActionForward execute( … ){ …. String rightName = “usera”; if(username.equalIsIgnoreCase(rightName)){ throw new AppModuleException(“user.login.error”, username); } … } 其中AppModuleException为自定义的继承了ModuleException的异常类。 扩展ModuleException的缺点: ModuleException的缺点在于它是Struts的控制层组件,不能被业务模型层使用。 根据模型层不依赖于控制层的原则,在模型层中不能引入Struts API的类。所以,对于同一种类型的异常 ,必需在模型层和控制层中创建两个独立的异常类,这样势必又会造成代码重复。 解决此类问题的方法就是采用Struts的配置异常处理。 配置 示例 input=“/index.jsp” > key=“login.error” path=“/index.jsp” type= “exp.AuthenticationFailedException” > 例中配置了一action的映射,如果该Action在调用业务对象时捕获到 AuthenticationFailedException时,并将之抛出,ActionServlet将会根据 的处理。 其中key指定义了异常的错误信息代码。 path指定了出现异常时转向的URI. type指定的对应的捕获异常的类型。 检查 type用于指待处理的异常类 hander指定异常处理类,缺少为的Struts中的ExceptionHandler类,如果设置为用户自定义异常处理类, 则该类必需继承ExceptionHandler。 path指定转发的路径。 key指定错误消息key,Struts根据该Key到Resource Bundle中寻找匹配的消息文本。 bundle指定Resource Bundle,如果不设置采用的就是默认Resource Bundle。 scope指定产生的ActionErrors或ActionMessages的存放范围。 分析Struts异常处理过程: Struts框架在调用processActionPerform时捕获并处理异常。 protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException { try { return (action.execute(mapping, form, request, response)); } catch (Exception e) { return (processException(request, response, e, form, mapping)); } } processException中对异常进行处理。 首先查看是否存在ExceptionConfig对象,该对象与配置文件中的 如果不存在,就继续向上抛出异常,如果存在则调用其getHander()方法获取异常处理对象 (ExceptionHander对象),最后调用其execute执行异常处理。 org.apache.struts.action.ExceptionHander为Struts中的默认异常处理类,它的execute方法负责处理 异常。 提示:通过扩展它可实现自定义的异常处理类以适应业务层的异常。