struts2的教程

这个是2008年左右的时候,给一培训机构讲课时候的课堂教学大纲,当时给学生讲解这些的时候都是现场编写代码,通过net meeting的方式将屏幕共享给学生。

这里着重展示了struts2的各种功能特性,希望能对学习struts2的朋友们有所帮助。

当年也和csdn合作录制了一期struts2的在线教学视频,也被盗版了...链接如下:http://www.verycd.com/topics/2760319/


书归正传:

Strusts2教程

孔庆祝

Struts2Struts1.x的全面比较

为了对Struts2Strtus1.x进行全面的比较,让读者了解这两种框架各自的优缺点,以便于在自己的项目中,根据实际情况,选择合适的框架,对它们两者进行比较,总结了如下表分析比较。

特性

Struts1.x

Struts2

Action

Struts1.x要求Action类要扩展自一个抽象基类。Struts1.x的一个共有的问题是面向抽象类编程而不是面向接口编程。

Struts2Action类实现了一个Action接口,连同其他接口一起来实现可选择和自定义的服务。Struts2提供一个名叫ActionSupport的基类来实现一般使用的接口。当然,Action接口不是必须的。任何使用execute方法的POJO对象可以被当作Struts 2Action对象来使用。

线程模型

Struts1.x Action类是单例类,因为只有一个实例来控制所有的请求。单例类策略造成了一定的限制,并且给开发带来了额外的烦恼。Action资源必须是线程安全或者同步的。

Struts2 Action对象为每一个请求都实例化对象,所以没有线程安全的问题。(实践中,servlet容器给每一个请求产生许多丟弃的对象,并且不会导致性能和垃圾回收问题)。

Servlet 依赖

Struts1.xAction类依赖于servlet API,当Action被调用时,以HttpServletRequestHttpServletResponse作为参数传给execute方法。

Struts2Action和容器无关。Servlet上下文被表现为简单的Maps,允许Action被独立的测试。Struts2Action可以访问最初的请求(如果需要的话)。但是,尽可能避免或排除其他元素直接访问HttpServletRequestHttpServletResponse

易测性

测试Struts1.x的主要问题是execute方法暴露了Servlet API这使得测试要依赖于容器)。第三方的扩展,如Struts TestCase,提供了一套Struts1的模拟对象(来进行测试)。

Struts2Action可以通过初始化、设置属性、调用方法来测试。依赖注入的支持也是测试变得更简单。

捕获输入

Struts1.x使用ActionForm对象来捕获输入。象Action一样,所有的ActionForm必须扩展基类。因为其他的JavaBean不能作为ActionForm使用,开发者经常创建多余的类来捕获输入。DynaBeans可以被用来作为替代ActionForm的类来创建。但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。

Struts2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己()属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven特性简化了taglibPOJO输入对象的引用。

表达式语言

Struts1.x整合JSTL,所以它使用JSTL的表达式语言。表达式语言有基本的图形对象移动,但是对集合和索引属性的支持很弱。

Struts2使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL)

将值绑定到页面

Struts1.x使用标准JSP机制来绑定对象到页面上下文。

Struts2使用“ValueStack”技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。

类型转换

Struts1.xActionForm属性经常都是StringStruts 1.x使用Commons-Beanutils来进行类型转换。转换每一个类,而不是为每一个实例配置。

Struts2使用OGNL进行类型转换。提供基本和常用对象的转换器。

验证

Struts1.x支持在ActionFormvalidate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。

Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性

Action执行控制

Struts1.x支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。

Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

 

整体架构图:

 

 

一、开始第一个struts2的应用:

1、 创建struts2应用的步骤:

1)、创建web工程导入jar包

2)、给web.xml添加过滤器

3)、给struts2工程的src下增加运行时配置文件struts.properties和action配置文件struts.xml,可以将不同的模块分切成不同的xml文件,在struts.xml引用

4)、写struts2的action

5)、写struts2的jsp页面

   2、需要注意的点:

    1)、web.xml中过滤器的名字一定要统一,class名字要写正确。例如:

    <filter>

        <filter-name>hdssh2</filter-name>

        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>

        <init-param>

            <param-name>actionPackages</param-name>

            <param-value>com.hc360.action</param-value>

        </init-param>

    </filter>

    <filter-mapping>

        <filter-name>hdssh2</filter-name>

        <url-pattern>/*</url-pattern>

</filter-mapping>

2)struts.properties中的devMod设置为开发模式;定义struts.i18n.reload=true;

struts.custom.i18n.resources=message

struts.devMode = true

3)、struts分割的不同的开发模块需要写正确,否则我们的filter将启动不起来

标准样子如下:注意其中如果要使用默认的拦截器一定要includestruts-default.xml如果想整个文档被读取,一定要声明dtd

4)、写你的页面的时候不要忘记给你的jsp页面加上:<%@taglibprefix="s"uri="/struts-tags"%>,这样才能正确使用struts2的标签

<!DOCTYPEstrutsPUBLIC

     "-//ApacheSoftware Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <includefile="struts-default.xml"/>   

     <packagename="default"extends="struts-default"namespace="/User">

        <actionname="user"class="com.knight.action.UserAction"method="execute">

         <interceptor-refname="paramsPrepareParamsStack"/>

         <resultname="success">/jsp/success.jsp</result>

         <resultname="input">/jsp/user/addUser.jsp</result>

         <resultname="list">/jsp/user/listUser.jsp</result>

         <resultname="re"type="redirect">User/user!listUser.action</result>

        </action>

     </package>

 </struts>

3、 备注

Struts.properties属性的详细解释:

struts.action.extension
          The URL extension to useto determine if the request is meant for a Struts action 
          
URL扩展名来确定是否这个请求是被用作Struts action,其实也就是设置 action的后缀,例如login.do'do'字。

struts.configuration
         The org.apache.struts2.config.Configuration implementation class
            org.apache.struts2.config.Configuration
接口名

struts.configuration.files
         A list of configuration files automatically loaded by Struts 
           struts
自动加载的一个配置文件列表

struts.configuration.xml.reload
         Whether to reload the XML configuration or not
          
是否加载xml配置(true,false)

struts.continuations.package
          The package containing actions that use Rife continuations
          
含有actions的完整连续的package名称

struts.custom.i18n.resources
         Location of additional localization properties files to load 
           
加载附加的国际化属性文件(不包含.properties后缀)

struts.custom.properties
         Location of additional configuration properties files to load
          
加载附加的配置文件的位置
struts.devMode
         Whether Struts is in development mode or not
          
是否为struts开发模式

struts.dispatcher.parametersWorkaround
         Whether to use a Servlet request parameter workaround necessary for someversions of WebLogic
           
(某些版本的weblogic专用)是否使用一个servlet请求参数工作区(PARAMETERSWORKAROUND

struts.enable.DynamicMethodInvocation
         Allows one to disable dynamic method invocation from the URL
            
允许动态方法调用

struts.freemarker.manager.classname
         The org.apache.struts2.views.freemarker.FreemarkerManager implementationclass 
          org.apache.struts2.views.freemarker.FreemarkerManager
接口名

struts.i18n.encoding
         The encoding to use for localization messages
          
国际化信息内码

struts.i18n.reload
         Whether the localization messages should automatically be reloaded
           
是否国际化信息自动加载

struts.locale
         The default locale for the Struts application
           
默认的国际化地区信息

struts.mapper.class
         The org.apache.struts2.dispatcher.mapper.ActionMapper implementation class
            org.apache.struts2.dispatcher.mapper.ActionMapper
接口

struts.multipart.maxSize
         The maximize size of a multipart request (file upload)
           multipart
请求信息的最大尺寸(文件上传用)

struts.multipart.parser
         The org.apache.struts2.dispatcher.multipart.MultiPartRequest parserimplementation for a multipart request (file upload) 
         
专为multipart请求信息使用的org.apache.struts2.dispatcher.multipart.MultiPartRequest解析器接口(文件上传用)
struts.multipart.saveDir
         The directory to use for storing uploaded files 
          
设置存储上传文件的目录夹

struts.objectFactory
         The com.opensymphony.xwork2.ObjectFactory implementation class
           com.opensymphony.xwork2.ObjectFactory
接口(spring

struts.objectFactory.spring.autoWire
         Whether Spring should autoWire or not
          
是否自动绑定Spring

struts.objectFactory.spring.useClassCache
         Whether Spring should use its class cache or not
          
是否spring应该使用自身的cache

struts.objectTypeDeterminer
         The com.opensymphony.xwork2.util.ObjectTypeDeterminer implementation class
            com.opensymphony.xwork2.util.ObjectTypeDeterminer
接口

struts.serve.static.browserCache
          If static content servedby the Struts filter should set browser caching header properties or not 
          
是否struts过滤器中提供的静态内容应该被浏览器缓存在头部属性中

struts.serve.static
         Whether the Struts filter should serve static content or not 
          
是否struts过滤器应该提供静态内容

struts.tag.altSyntax
          Whether to use thealterative syntax for the tags or not 
          
是否可以用替代的语法替代tags

struts.ui.templateDir
          The directory containingUI templates
           UI templates
的目录夹

struts.ui.theme
          The default UI templatetheme
          
默认的UI template主题

struts.url.http.port
          The HTTP port used byStruts URLs
          
设置http端口

struts.url.https.port
          The HTTPS port used byStruts URLs 
          
设置https端口

struts.url.includeParams
          The defaultincludeParams method to generate Struts URLs 
         
url中产生 默认的includeParams

struts.velocity.configfile
          The Velocityconfiguration file path
           velocity
配置文件路径

struts.velocity.contexts
          List of Velocity contextnames
           velocity
context列表


struts.velocity.manager.classname
         org.apache.struts2.views.velocity.VelocityManager implementation class
          org.apache.struts2.views.velocity.VelocityManager
接口名

struts.velocity.toolboxlocation
          The location of theVelocity toolbox
           velocity
工具盒的位置
struts.xslt.nocache
          Whether or not XSLTtemplates should not be cached
          
是否XSLT模版应该被缓存  

 

4、 Struts默认的拦截器以及result配置(查看源代码目录下的struts-default.xml

 

二、使用struts2进行增删改查(不带验证的crud)

1、 步骤:

1)、建立针对某个对象crud的action对象

2)、参数绑定以及预先获取参量,以及ModelDriven,Preparable的使用

2、 需要注意的地方:

1)、如果针对这个模块的配置文件写错,或者没有声明doctype,那么整个工程都不会启动

2)、action标签的写法

3)、package标签你可以发挥的地方

4)、针对具体的action中的拦截器的使用,不要使用默认的那个,要是使用        <interceptor-refname="paramsPrepareParamsStack"/>

3、 如何防止刷新提交?result的妙用,指定result的type为特定值

三、如何获取我们常用的request,response,session

1、 常规方法:(拦截器已经为我们将这些都封装好了)

     HttpServletRequestrequest = ServletActionContext.getRequest();
      HttpServletResponse response = ServletActionContext.getResponse();

2、 IOC的方法:(要实现几个接口implements SessionAware, ServletRequestAware, ServletResponseAware

在action中使用:

     private HttpServletRequest request;
   
private HttpServletResponse response;  

并加上他的settergetter方法就ok了。拦截器也是已经为我们封装好了

四、使用struts2进行action的单元测试

1、步骤

1)、增加junit.jar的包

2)、写一个teset类,继承testCase

3)、创建action对象,并使用action对象进行值的设定,然后进行断言判定

2、演示:

五、为struts2写自己的拦截器

1、 步骤

1)、添加一个拦截器的类,这个类继承AbstractInterceptor类,写当前类的操作逻辑

2)、在package下声明这个拦截器,例如:

 <interceptors>

<interceptorname="auth"class="com.knight.interceptor.CheckLoginInterceptor"/>

 </interceptors>

3)、在action中引用次拦截器来对action中的所有方法进行拦截

          <interceptor-refname="auth"/>

   <interceptor-refname="paramsPrepareParamsStack"/>

2、 通过定义自己的拦截器来演示我们在action前后进行的操作

3、 拦截器的使用注意点:

如果你不定义拦截器,那么他默认的将使用struts-default.xmldefaultStack

4、 系统默认提供的拦截器介绍

5、 在package下定义自己的拦截器队列

<packagename="my"extends="struts-default"namespace="/manage">

        <interceptors>

        <!--定义拦截器 -->

        <interceptorname="拦截器名"class="拦截器实现类"/>

        <!--定义拦截器栈 -->

        <interceptor-stackname="拦截器栈名">

             <interceptor-ref name="拦截器一"/>

             <interceptor-ref name="拦截器二"/>

        </interceptor-stack>

        </interceptors>

       ......

</package>

 

6、 拦截器拦截显示图

六、使用struts2进行国际化

1、 简单的国际化(就是定义国际化文件,我们在页面取出)

1)、定义国际化文件在src目录下:message_en_US.propertiesmessage_zh_CN.properties

2)、在struts.properties中定义国际化文件的基础名称,上边就应当定义为:struts.custom.i18n.resources=message

3)、在页面进行简单的国际化文件取得

例如:<h2><s:textname="Hello"/></h2>

        <h2><s:propertyvalue="%{getText('Hello')}"/></h2>

2、 做出切换语言的方法,让用户可以直观的看到国际化结果

开发国际化的应用程序时,有一个功能是必不可少的——让用户快捷地选择或切换语言。在Struts 2.0中,通过ActionContext.getContext().setLocale(Localearg)可以设置用户的默认语言。不过,由于这是一个比较普遍的应用场景(Scenario),所以Struts 2.0为您提供了一个名i18n的拦截器(Interceptor),并在默认情况下将其注册到拦截器链(Interceptor chain)中。它的原理为在执行Action方法前,i18n拦截器查找请求中的一个名为"request_locale"的参数。如果其存在,拦截器就将其作为参数实例化Locale对象,并将其设为用户默认的区域(Locale),最后,将此Locale对象保存在session的名为“WW_TRANS_I18N_LOCALE”的属性中。

1)、定义一个javabean来获取国际化的语言列表

publicclass Locales {

    public Map<String,Locale> getLocales() {

       Map<String, Locale> locales =new Hashtable<String, Locale>(2);

       locales.put("American English", Locale.US);

       locales.put("SimplifiedChinese", Locale.CHINA);

        return locales;

    }

}

2)、定义一个可以被其他页面包含的国际化语言选择页面LangSelector.jsp

<scripttype="text/javascript">

    functionlangSelecter_onChanged(){

        document.langForm.submit();

}

</script>

<s:setname="SESSION_LOCALE"value="#session['WW_TRANS_I18N_LOCALE']"/>

<s:beanid="locales"name="com.knight.util.Locales"/>

<formaction="<s:urlincludeParams="get"encode="true"/>"name="langForm"

    style="background-color: powderblue; padding-top: 4px;padding-bottom: 4px;">

    Language: <s:select label="Language"

        list="#locales.locales"listKey="value"   listValue="key"

        value="#SESSION_LOCALE == null ? locale :#SESSION_LOCALE"

        name="request_locale"id="langSelecter"

        onchange="langSelecter_onChanged()"theme="simple"/>

</form>

<s:property value="#SESSION_LOCALE"/>

      3)、将当前页面被其他页面引用:

    <divstyle="border:1pxsolid #fff000">

    <s:includevalue="LangSelector.jsp"/>

    </div>

3、 国际化需要注意点:

1)、将struts.properties中的struts.i18n.reload=true;在开发期间设置成true,这样更改国际化文件就不需要重启服务器了

2)、不要忘记给你的jsp页面加上<%@taglib prefix="s"uri="/struts-tags"%>标签,这样页面才能使用struts2的标签库!

4)、普通文件国际化资源查找顺序以及位置

1.    使用全局的资源文件,方法如上例所示。这适用于遍布于整个应用程序的国际化字符串,它们在不同的包(package)中被引用,如一些比较共用的出错提示;

2.    使用包范围内的资源文件。做法是在包的根目录下新建名的package.propertiespackage_xx_XX.properties文件。这就适用于在包中不同类访问的资源;

3.    使用Action范围的资源文件。做法为Action的包下新建文件名(除文件扩展名外)与Action类名同样的资源文件。它只能在该Action中访问。如此一来,我们就可以在不同的Action里使用相同的properties名表示不同的值。例如,在ActonOnetitle动作一,而同样用titleActionTwo表示动作二,节省一些命名工夫;

使用<s:i18n>标志访问特定路径的properties文件。在您使用这一方法时,请注意<s:i18n>标志的范围。在<s:i18nname="xxxxx"></s:i18n>之间,所有的国际化字符串都会在名为xxxxx资源文件查找,如果找不到,Struts 2.0就会输出默认值(国际化字符串的名字)。这里有一个bug,假如你的指定的文件名称放到其他文件后边被加载,他将覆盖最先被加载的国际化文件。导致前边的输出有误。假如我要使用<s:i18n name=”test”>那么我将这样定义我的struts.properties: struts.custom.i18n.resources=test,message

5)、struts2查找资源顺序(这里我验证了如果他是继承ActionSupport是这样查找的)

以上的顺序在继承ActionSupport类的时候适用:具体描述如下:

假设我们在某个ChildAction中调用了getText("user.title")Struts 2.0的将会执行以下的操作:

1.   查找ChildAction_xx_XX.properties文件或ChildAction.properties

2.   查找ChildAction实现的接口,查找与接口同名的资源文件MyInterface.properties

3.   查找ChildAction的父类ParentActionproperties文件,文件名为ParentAction.properties

4.   判断当前ChildAction是否实现接口ModelDriven。如果是,调用getModel()获得对象,查找与其同名的资源文件;

5.   查找当前包下的package.properties文件;

6.   查找当前包的父包,直到最顶层包;

7.   在值栈(Value Stack)中,查找名为user的属性,转到user类型同名的资源文件,查找键为title的资源;

8.   查找在struts.properties配置的默认的资源文件,

9.   输出user.title

七、使用struts2进行验证

1、 验证种类以及方法

1)、分为客户端验证和服务器端验证,都需要“action名称-validation.xml”文件的支持,这个xml文件是客户端验证脚本生成依据,同时也是服务器端验证的基础依据。

2)、注意我们的xml文件的doctype的声明,如果没有他,那么这个xml文件将不起作用。

2、 Java服务器端验证需要做的事情

声明验证方法,总的方法validate(),和针对某个action中的某一项验证的方法:validateMethodName();一般在这两个验证方法中写逻辑的验证,如果出现不符合逻辑的事情使用addFieldError("group.num","人为造成num错误,数字大于100行不?");

3、 客户端验证

客户端验证需要使用<s:form 标签,指定validate=“true”;同时并指定struts.properties的theme=xhtml。这样能促使生成客户端的验证脚本。脚本的生成使用了“action名称-validation.xml”文件。

 

4、 验证的具体流程图


5、 验证顺序

配置文件查找顺序

在上面的例子中,我们通过创建ValidationAction-validation.xml来配置表单校验。Struts 2.0的校验框架自动会读取该文件,但这样就会引出一个问题——如果我的Action继承其它的Action类,而这两个Action类都需要对表单数据进行校验,那我是否会在子类的配置文件(Xxx-validation.xml)中复制父类的配置吗?

不同的是校验框架按照自上而下的顺序在类层次查找配置文件。假设以下条件成立:

1.   接口 Animal;

2.   接口 Quadraped扩展了 Animal;

3.    AnimalImpl实现了 Animal;

4.    QuadrapedImpl扩展了 AnimalImpl实现了 Quadraped;

5.    Dog扩展了 QuadrapedImpl;

如果Dog要被校验,框架方法会查找下面的配置文件(其中别名是Actionstruts.xml中定义的别名):

1.   Animal-validation.xml

2.   Animal-别名-validation.xml

3.   AnimalImpl-validation.xml

4.   AnimalImpl-别名-validation.xml

5.   Quadraped-validation.xml

6.   Quadraped-别名-validation.xml

7.   QuadrapedImpl-validation.xml

8.   QuadrapedImpl-别名-validation.xml

9.   Dog-validation.xml

10.  Dog-别名-validation.xml

6、 已经有的校验器,(这个是webwork中用的)

<validators>
   
<validatorname="required"class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
   
<validatorname="requiredstring"class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
   
<validatorname="int"class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
   
<validatorname="double"class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
   
<validatorname="date"class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
   
<validatorname="expression"class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
   
<validatorname="fieldexpression"class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
   
<validatorname="email"class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
   
<validatorname="url"class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
   
<validatorname="visitor"class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
   
<validatorname="conversion"class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
   
<validatorname="stringlength"class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
   
<validatorname="regex"class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
</validators>

7、 ActionSupport在验证中到底扮演一个什么角色:

ActionSupport类是一个工具类,它已经实现了Action接口。除此之外,它还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2Action开发。
Validatable接口中定义了一个validate()方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类的fieldErrors域中,然后通过OGNL表达式负责输出。

ActionSupport类已经提供了国际化信息的能力,它提供了一个getTextString key)方法,该方法用于从资源文件中获取国际化信息。

八、使用struts2验证的国际化

1、 如何让我们的验证失败信息国际化

 继承ActionSupport类,针对出现的错误进行国际化处理

2、 在“actionName-validation.xml”文件中直接从国际化的信息文件中取值

3、 这个验证文件的写法如下:(不要丢掉他的doctype声明)

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEvalidators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN""http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">         

<validators>

   <fieldname="group.name">

       <field-validatortype="stringlength">

        <paramname="trim">true</param>

        <paramname="minLength">3</param>

        <paramname="maxLength">10</param>

        <message>长度要超过3-10之间呀!</message>

       </field-validator>

        <field-validatortype="requiredstring">

        <message>不允许为空</message>

        </field-validator>

    </field>

    <fieldname="group.num">

        <field-validatortype="int">

        <!--

        <paramname="min">20</param>

        <messagekey="invalid.fieldvalue.num"></message>

         -->

         <paramname="min">2</param>

         <paramname="max">100</param>

         <message>数值在${min}-${max}之间</message>

        </field-validator>

    </field>

</validators>

九、使用struts2进行附件上传

1、 需要设置的参数

2、 Web.xml增加的定义

3、 你上传目录文件的简历

4、 加上限定的图片上传

十、其他

你可能感兴趣的:(struts2的教程)