struts2学习笔记

struts是一个开源的Java Web开发框架,提供MVC体系结构,以及其他工具比如常用的标签、表单数据的验证等。是Java开发中应用最广泛的MVC框架。

一、MVC模式

 Web应用程序由servlet、jsp等组成,在早期的web应用中,Servlet、Jsp中既包含与数据库交互的代码,又包括HTML、CSS等页面代码,还包括复杂的业务逻辑层代码。页面代码负责接受处理客户端请求,对请求处理后直接做出响应,用少量的JavaBean来处理数据库连接、数据库访问等操作。这种模式简单被称为模式一(Model1),适用于快速开发小规模项目。但从工程化的角度来看,代码耦合率高,程序的层次、清晰度混乱,也就带来维护、开发成本较高。

后来人们引入MVC(Model-View-Controller)体系结构,将不同概念的代码分离开来,Model层包括业务逻辑代码与数据库代码;View层包括数据的展示代码,如Html、CSS样式表、JSP标签等;Controller层连接model层与view层,从Model层获取数据,送到View层显示。这就是我们常讲到的Model2模式的思想,将Servlet作为前端控制器,负责接收客户端发送的请求,在Servlet中只包含控制逻和简单的前端处理;然后调用后端JavaBean来完成实际的逻辑处理;最后转发到相应的JSP页面处理现实逻辑。这种设计模式更适用于大规模应用的开发,但也增加了复杂程度。

Web模式下的MVC思想我们将视图注册给模型,当模型数据发生改变时,即时通知视图页面发生改变,这便是struts的思想。struts2是一个优秀的MVC框架,它提供无浸入式设计,并提供拦截器可进行权限拦截,无须自己实现类型转换,而且支持多种视图技术,如JSP、Freemaker,Velocity等诸多功能使其具有巨大吸引力。 

二、Struts2的原理及流程

编写struts2的过程是在web.xml文件中定义核心Filter来拦截用户请求,让该框架介入Web应用中,如下配置:

    <filter>

          <filter-name>struts2</filter-name>
          <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
       </filter>
       <filter-mapping>
          <filter-name>struts2</filter-name>
          <url-pattern>/*</url-pattern>

            </filter-mapping> 

如果需要以POST方式提交请求,则需定义包含表单数据的JSP页面,如果仅仅只是以GET方式发送请求,则无须经过这一步。需要用户自己定义处理请求的Action类,并在struts.xml文件中配置这些action,将处理结果和物理视图资源之间对应起来,最后编写视图资源,如果action需要把一些数据传给视图资源,则可以借助于OGNL表达式。 

下面的图是struts处理用户完整一次请求响应的流程:

  

StrutsPrepareAndExecuteFilter和XxxAction共同构成了Struts2的控制器,常常把StrutsPrepareAndExecuteFilter称为核心控制器,把XxxAction称为业务控制器。从图中看出,业务控制器XxxAction通常并不与物理视图关联,只负责返回处理结果,而该处理结果与怎样的视图关联,依然由StrutsPrepareAndExecuteFilter来决定。这样的好处是:如果有一天需要将某个视图名映射到不同视图资源,无须修改XxxAction的代码,而是只需要改配置文件即可。在Struts2框架的控制下,用户请求不再向JSP页面发送,而是由核心控制器StrutsPrepareAndExecuteFilter来调用JSP页面来生成响应,其实是将请求forward到指定jsp页面。

三、Action的配置和实现

 在Struts2中,Action是应用的核心,我们可以选择自己实现struts2的接口,也可以不实现。struts2的Action类可以是一个普通的POJO,Struts2通常直接使用Action来封装HTTP请求参数,因此Action类里还应用包含与请求参数对应的属性,并且为这些属性提供对应的setter和getter方法。当然它还提供了一个Action接口,我们需要实现execute方法,其返回一个字符串,在配置文件里对应不同的视图。Struts2本身为Action接口提供了一个实现类:ActionSupport,它是默认的Action实现类,提供了许多默认方法,它也是Struts2默认的Action处理类,使用时可以直接继承该类。

1)访问ServletAPI 

在Struts2中提供三个接口HttpServletRequest,HttpSession,ServletContext来访问ServletAPI,分别代表了JSP内置对象中的request,session和application。在Struts2中提供了一个ActionContext类,通过该类可以访问ServletAPI,其常用的方法为:get,getApplication,getContext,getParameters,getSession等,使用该方法不是直接获取Servlet API的实例。

Struts2提供以下接口,可以直接访问实例:ServletContextAware,ServletRequestAware,ServletResponseAware。

Struts2还提供了一个ServletActionContext工具类,这个类包含几个静态方法 getPageContext,getRequest,getResponse,getServletContext等。借助于工具类的帮助,Action可以不必与ServletAPI耦合,因此更加简单。 

2)调用Action

我们要把写好的Action类在Struts.xml文件中配置,配置方式类似:

 <package name="demo" namespace="/test" extends="struts-default">

<action name="loginPerson" class="com.demo.action.LoginAction" method="login">

<result name="success">/WEB-INF/page/welcome.jsp</result> 

<result name="error">/WEB-INF/page/message.jsp</result>
</action>
</package>

 在执行Action的非默认方法时,可以使用action!method.action的URL形式访问,其中,action为struts.xml文件中配置的Action名字,method为Action的方法名,中间用“!”隔开,例如:http://lcoalhost:8080/struts2/test/loginPerson!login.action 将执行loginPerson的login方法。

可以DMI和通配符来调用action,如果我们要在一个action中包含多个处理逻辑,并通过为表单元素指定不同Action属性来提交给action的不同方法,应使用动态调用方法!动态方法调用是指表单元素的action并不是直接等于某个Action的名字,而是以如下形似来指定表单的action属性:action=“ActionName!methodName” 。

而使用通配符通常如下:

<package name="main" extends="struts-default">

<action name="*Book" class="com.demo.action.BookAction" method="{1}" >

<result>/success.jsp</result>

<result name="{1}">/{1}Book.jsp</result>

<result name="error">/message.jsp</result> 

</action>

</package>

在调用时使用如 listBook.action。 该方法可以把一个类的方法映射为多个action。

3)配置处理结果

 Action的结果配置是告诉框架,当Action处理结束时,系统下一步应该做什么,系统下一步应该调用哪个物理视图资源来显示处理结果。struts2中提供两种结果,局部结果:将<result..../>作为<action....../>元素的子元素配置,全局结果:将<result..../>作为<global-results..../>元素的子元素配置。配置结果通常需要指定两个属性:name和type,struts2内建的支持结果类型如下:chain,dispatcher,freemaker,httpheader,redirect,redirectAction,stream,velocity,xslt,plainText

4)配置异常处理

如果我们在执行方法上抛出异常的,则我们是把异常抛给了struts2来框架处理,struts2框架接收到action抛出的异常之后,将根据Struts.xml文件配置的异常映射,转入指定的视图资源。配置方式:局部异常映射,将<exception-mapping.../>元素作为<action..../>元素的子元素配置,全局异常映射,将<exception-mapping..../>元素作为<global-exception-mappings>元素的子元素配置,局部异常会覆盖掉全局异常映射。需要指定两个属性 exception和result属性。 

5)配置常量及配置文件 

struts.xml文是struts2的默认配置文件,该文件通常放在WEB-INF/classes路径下,该配置文件主要是配置Action和请求之间的对应关系,并配置逻辑视图和物理视图资源之间的对应关系。除此之外,还有一些额外的功能,如Bean配置,配置常量,导入其他配置等。对于常量的配置,struts.properties也是一个配置文件,并且配置了大量的常量。如常用的struts.action.extension。struts2框架按如下搜索顺序加载struts2常量的:struts-default.xml,struts-plugin.xml,struts.xml,struts.properties,web.xml,如果多个文件中常量重复则后一个会覆盖前一个的。为了避免struts.xml文件过于庞大,我们可以将配置按模块不同写在不同的文件中,然后再通过include手动导入。<include file="struts-part1.xml />  <include file="struts-part2.xml/>。

四、类型转换器Converter

所有的mvc框架,都需要负责解析HTTP请求参数,并将请求参数传给控制器组件。但是由于http请求参数都是字符串,而java是强类型语言,因此mvc框架需要将这些字符串转换成相应的数据类型。struts2提供了强大的类型转换机制,我们可以使用OGNL表达式,也可自定义转换器。struts2提供了TypeConverter接口,并提供了实现类DefaultTypeConverter,我们只需要继承该类,重写convertValue方法就可简单实现转化器了。

我们还需要注册类型转换器,对于局部类型转换器在局部类型转换文件中添加一行: <propName>=<ConverterClass> ,命名方法为ActionName-Conversion.propertie,放在action类的包下;全局类型转换器我们要提供了一个xwork-conversion.properties文件,同样逐行加入对应类型。

五、校验器Validator

 struts2提供了数据校验功能,客户端校验主要是过滤正常用户的误操作,主要通过javascript代码完成;服务器校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现。我们可以通过手工编写校验,需要在继承ActionSupport时重写validate()方法,如果失败的话转发给input视图,调用addFieldError()方法添加错误信息,如果系统的fieldError包含失败信息,在input视图中可以通过<s:fielderror/>显示失败信息。如果对指定的方法校验,则需要编写validateXXX()方法,来校验XXX方法。

 还有一种方法是xml配置,此中配置也包括全局配置和局部配置,全局校验ActionName-validation.xml或者ActionName-aliasName-validation.xml,局部校验ActionClassName-ActionName-validation.xml。在xml中可以配置很方便,可以对数字,日期,正则表达式等校验。

另外如果两个文件同时存在,则会汇总规则,如果出现了冲突,则使用局部的配置,而Action继承父类,会先寻找父类的配置文件。 

六、拦截器Interceptor

 struts2拦截器由struts-default.xml,struts.xml等配置文件进行管理里,所有开发这可以扩展自己的拦截器。struts2框架提供了很多内置的拦截器,这个也需要我们自己去配置<interceptor name=""  class="" /> 还有相关联的标签<interceptors ....>,<interceptor-ref....>,<interceptor-stack....>。类似的配置如下:

 <interceptors>

<interceptor name="permission"
class="com.demo.intercepter.PermissionIntercepter">
</interceptor>
<interceptor-stack name="permissionStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="permission" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="permissionStack" />

在action中使用时需要配置,如果我们要编写自己的拦截器则需要实现Interceptor接口,或者继承AbstractInterceptor类重写intercept方法,MethodFilterInterceptor可以实现方法过滤,重写doInterceptor方法。

七、文件上传fileupload

 为了实现上传文件,我们必须将表单的提交属性设置为POST,将entype设置为multipart/form-data,只要这种情况下,浏览器才会把用户选择文件的二进制数据发送给服务器。struts2提供了简单的封装。如果要同时上传多个文件的话,则需要在Action中指定File[]或者List<File>类型的变量,并使用多个同名的<struts:file/>标签即可。

八、国际化

 由于系统一般面向多种语言,因此我们要提供不同国家/语言环境的消息资源,然后通过ResourceBundle加载指定Locale对应的资源文件,再取得该资源文件中指定key对应的消息。struts2提供了很多加载国际化资源的文件的方式,分别在全局范围,包范围,action范围。全局配置常量<constant name="struts.custom.i18n.resources" value="baseName" />,baseName_language_country.properties。包范围package_language_country.properties,Action范围ActionName_language_country.properties,直接访问:

<s:i18n name="test" >

<s:text name="welcome" /> 

</s:i18n>

 国际化资源的访问使用ActionSupport类的getText()方法,还可以输出使用占位符的国际化消息getText(String name,List/String[] args)。加载顺序是从小范围到大范围的原则。

九、OGNL表达式

struts2标签库主要使用OGNL语言,OGNL全称为Object-Graph Navigation Language,是一种操作对象属性的开源的表达式语言。相对于其他的表达式语言如EL等,OGNL有自己的优点:

能够访问对象的方法,例如list.size();能够访问静态属性与静态方法,方法是在类名前、方法前加上@。如@java.lang.Math@PI,@java.lang.String@format('foo %s','bar'); 支持赋值操作和表达式串联;如赋值#value=5;访问OGNL上下文(OGNL context)和ActionContext(所有的Servlet资源);操作集合对象。

OGNL语法类似于EL,主要使用“." 作为操作符。例如要访问person.getCountry().getName()可以这样写:person.country.name。在访问POJO属性上,OGNL与EL表达式是完全一样的。OGNL主要有三个符号:#、%与$。#是struts2标签中最常用的符号,主要有3种用途:

能够访问OGNL上下文与ActionContext资源,相当于ActionContext.getContext()。常用的“#”属性如下:

#parameters,代表request提交的所有参数,#parameters.id返回的是String[]类型,相当于JSP中的request.getParameterValues("id")。一般使用#parameters.id[0] ;

#request,代表request里的所有属性,#request.account相当于JSP中的request.getAttribute("account");

#session,代表session里的所有属性,#session.account相当于JSP中的session.getAttribute("account");

#application,代表ServletContext里的所有属性,#application.account相当于JSP中的application.getAttribute("account");

#attr,代表request或session或application的所有属性,#attr.account相当于EL表达式中的${account} ,依次查request、session、application的属性,直到找到为止。

此外#还可以过滤或筛选集合,例如:books.{?#this.price<20},表示所有的price<20的书。最后一种用途是构造Map,如#{'foo1':‘bar1’,'foo2':'bar2'} 。

%用于表示某字符串为一个OGNL表达式。某些标签中既能接受字符串,又能接收OGNL表达式。标有%的被当做OGNL表达式并被执行,没有标有%的被当做普通的字符串。如:

<struts:label label="#request.account"></struts:label>   参数为普通字符串,输出字符串#request.account

<struts:label label="%{#request.account}"></struts:label>   用%表示参数为OGNL,输出request的account属性。

$主要用于在资源国际化文件中或者struts.xml中引用OGNL表达式。

十、struts标签 

struts2提供了一套标签库用于简化JSP层的编程,开发者只需在标签中做少量的设置,就可以实现各种常用的效果。使用标签库,struts2会自动完成JSP层的显示数据、在Action层采集数据等工作。struts2的标签都在统一包含在struts-tags.tld文件中,都是用统一的前缀,从功能上讲,struts2标签库大致分为控制标签、数据标签、表单UI标签、非表单UI标签等。

控制标签用于控制流程,如判断、遍历等。控制标签是struts2中最常用的标签。if,else,elseif控制流程,前两个都有test属性,返回true或false。append标签用于将多个List连成一个List,相当于java中的list1.addAll(list2);generator标签将字符转化为List,相当于java中的split;iterator标签遍历集合;merge标签取集合的并集,subset标签用于筛选集合里元素,它使用一个Filter,将不合格的元素过滤掉,剩下原集合的一个子集。

数据标签包括javabean相关标签、资源国际化标签等,action标签包含action页面,相当于jsp中的include,参数ignoreContextParams表示是否将本页面的参数传递给被调用的Action;bean标签引用javabean,以便访问其getter、setter方法;date标签输出日期,属性format设置时间格式,属性nice可读性较好;i18n、text标签声明资源国际化,i18n标签指定资源文件,text标签指定资源的索引。include标签包含jsp页面,param标签传递参数,set标签设置变量值,property标签输出变量值。

表单UI标签,用于输入数据、提交数据。struts2标签库不仅博阿含常规的html空间如输入框、文本框、文件域等,还集成了常用的控件,例如日期时间控件,联动下拉框,自动填充下拉菜单等,这些常用控件是集成的dojo框架,是利用javascript实现的。form标签输出表单,textfield、textarea、file、checkbox、radio标签是最基本的表单标签,会生成html里的<input>标签。select、autocomplete标签下拉框,前者生成<select>标签,后者具有自动完成功能的下拉框,能根据所填的内容筛选下拉框的内容,使用时必须使用ajax主题。checkboxlist标签为可以多选的多个复选框,combobox标签用于生成一个组合框,datetimepicker标签是专门输入日期时间的输入框,它自带一个日历,可以指定日历格式,doubleselect标签为联动下拉框,选择第一个下拉框时,第二个下拉框的值会随第一个下拉框值的改变而改变。optiontransferselect标签左右各有一个列表,右边的选项可以转到左边,左边的选项可以转到右边。optiontransferselect标签式利用两个<select>实现的,optgroup标签用于给<select>的选项分组,optgroup标签可以生成<OptGroup>标签。

非表单UI标签只用于显示一些信息,而不会向Action提交数据。非表单UI标签中有一部分dojo提供的ajax控件,例如数、标签页等。debug标签输出调试信息,fielderror、actionerror、actionmessage标签显示错误信息,div、submit、a标签实现无刷新获取数据,tabbedPanel标签是struts2提供的标签页控件,tree标签用来输出树,如文件结构等,也可动态加载数据。 

posted on 2013-01-03 23:59  糊涂先生  阅读(441)  评论(0编辑  收藏  举报