Struts2入门

Struts2

简介

       由WebWork发展而来,也属于MVC框架,与Struts1有很大的区别。

优点

       1、不依赖与Servlet API,对比Struts1的execute方法的参数HttpServletRequest和HttpServletResponse

       2、提供了拦截器,便于AOP编程

       3、提供了类型转换器,可以把特殊请求的参数转换成需要的类型

       4、支持多种视图技术,如:jsp、freemarker、velocity等

       5、提供了输入校验,细分到方法的级别

       6、提供了i18n资源文件管理,可以细分到全局范围、包范围和action范围

搭建环境

       1、添加相关的jar文件

              struts2-core-2.x.x.jar:struts2的核心类库

              xwork-2.x.x.jar:xwork类库

              ognl-2.6.x.jar:OGNL表达式

              freemarker-2.3.x.jar:UI标签的模板

              commons-logging-1.1.x.jar:日志包

              commons-fileupload-1.2.1.jar:文件上传组件

       2、编写struts.xml配置文件

       3、在web.xml配置struts2启动

              Struts2通过过滤器标签启动的

struts配置:

       struts以包的形式管理action,包必须有一个name属性(包的名称在配置文件中必须唯一),可以有一个namespace(是action访问路径的一部分),访问时应该是namespace/action的name.action形式进行,每个包通常都应该继承struts-default包(该包提供了大量的拦截器和result类型,完成struts2的框架功能,在struts2-core-2.x.x.jar中的struts-default.xml中定义的),如果一个包有abstract="true"属性,则该包中不能包含action定义,只能被其他包继承。

       action中name指定了名称,class指定了类型,method指定了访问action类的方法(方法签名是:public String XX();),在页面中可以直接访问类中定义的getXXX方法(使用反射去调用的)

action的默认值:

       没有定义action的class属性,则默认为ActionSupport

       没有定义action的method属性,则默认为execute方法

       没有定义result的name属性,则默认为success

result视图转发类型:

       dispatcher(默认的):请求转发

       redirect(重定向到Jsp):

       redirectAction(重定向到Action):如果重定向到不同包的action,则需要如下:

              <resulttype="redirectAction">

                     <paramname="namespace">/命名空间名称</param>

                     <paramname="actionName">action名称</param>

              </result>

       plainText(显示原始文件内容):常用于查看源代码

              <resulttype="plainText">/xxx.jsp</result>

              也可以按如下设置:

              <result type="plainText">

                     <paramname="location">/xxx.jsp</param>

                     <paramname="charSet">UTF-8</param> <!-- 指定读取文件的编码 -->

              </result>

       可以在包内使用<global-results>定义包内的全局视图,供该包内的action使用

       可以定义一个抽象包,其中包含<global-results>,供其他包继承,从而达到所有包内的action都可以访问的全局视图

可以在action标签内,使用param子标签给action类的属性注入值,如:

       <actionname="xx" class="yy">

              <param name="属性名">属性值</param>

       </action>

可以在struts.xml配置文件中,使用<constantname="struts.action.extension" value="do,action"/>形式,改变请求路径的后缀为do或action等,注意:要求web.xml中<url-pattern>*</url-pattern>。

加载常量的顺序:

       struts-default.xml--> struts-plugin.xml --> struts.xml --> struts.properties -->web.xml

       后面定义的重名常量会覆盖前面的

       struts.i18n.encoding常量:指定默认的编码集

       struts.serve.static.browserCache常量:设置浏览器是否缓存

       struts.configuration.xml.reload常量:设置系统是否自动加载修改后的配置文件

       struts.devMode常量:是否开发模式

       struts.objectFactory常量:与spring集成时,确定由谁来创建action对象

       struts.multipart.maxSize常量:上传文件总大小的限制

struts2的处理流程:

       1、用户请求 --> 如果请求后缀是action,则跳转到struts2的框架中,否则不处理

       2、请求发送至StrutsPrepareAndExecuteFilter类

       3、经过一系列的拦截器(包含用户自定义的拦截器),这是struts2的核心部分

       4、送至action进行处理(struts1.x的action是单例模式,struts2的action是原型模式[每次都会创建一个新的action,是线程安全的])

       5、把处理结果和action的result进行对比

       6、跳转到相应的视图或action

可以把struts配置文件拆分成多个(一般以模块进行划分),然后struts配置文件中再使用include标签将其组合起来,以达到给配置文件减肥,方便管理的目的。

struts2中action的动态方法调用:

       1、可以使用【action!方法名.action】的方式(不推荐),如:

              原来:http://localhost:8080/项目名/命名空间/action名称.action                                                                     -->   调用action名称对应的方法

              动态:http://localhost:8080/项目名/命名空间/action名称!新方法名.action            --> 调用action类中的新方法

              可以使用struts.enable.DynamicMethodInvocation常量设置是否支持动态方法调用

       2、也可以通过通配符(*)定义action(推荐),如:

              <action name="xxx_*"class="yy" method={1}>

                     ...

              </action>

              其中在name属性中定义了action的名字,其中含有通配符,在method中可以依据下标(从1开始)得到对应的通配符所表示的内容。

              {1}的形式也可以在class属性值以及result属性值中使用,例如:

              动态:http://localhost:8080/项目名/命名空间/xxx_新方法名.action        -->  调用action类中的新方法

在struts2中接收请求参数:

       struts2通过在action类中定义一个与请求参数同名的属性,并提供setter方法,然后通过反射来得到请求参数。

       也可以说接收复合类型的参数,不过需要使用.进行分隔,如:person.id、person.name等

struts2中有2中类型转换器:(局部[对某个action起作用]和全局)

       自定义类型转换器必须继承DefaultTypeConverter类,重写其convertValue方法即可(双向转换)。

       局部的类型转换器:

              在action类所在的包中添加一个【action名称-conversion.properties】文件,并在其中声明属性和类型转换器的映射,即可以将用户自定义的类型转换器注册成一个局部的类型转换器。例如:

              public class DateConverter extendsDefaultTypeConverter{

                     privateSimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

                     //重写父类的方法(实现了双向转换)

                     publicObject convertValue(Map context,Object value,Class toType){

                            try{

                                   //把字符串转换成指定的类型

                                   if(toType== Date.class){

                                          String[] params = (String[])value; // 必须把请求参数转成字符串数组(因为请求参数可能是一组多选框的值)

                                          return sdf.parse(params[0]);

                                   }

                                   //把指定的类型转成字符串

                                   elseif(toType == String.class){

                                          Date date = (Date)value;

                                          return sdf.format(date);

                                   }

                            }catch{

                            }

                            return null;

                     }

              }

              在XXXaction的包内的XXXaction-conversion.properties文件中:

              #指定XXXaction的birthday属性使用的转换器

              birthday=com.phome.converter.DateConverter

       全局类型转换器:

              在src目录下添加一个【xwork-conversion.properties】文件,在其中编写内容如下:

              #数据类型 = 转换器类型

              java.util.Date=com.phome.converter.DateConverter

访问Application、session和request对象

       1、得到模拟对象

              ActionContext ctx =ActionContext.getContext();

              ctx.getApplication()       --> 得到表示application的map集合

              ctx.getSession()                          -->得到表示session的map集合

              ctx                                                                                              --> 得到表示request的map集合

       2、得到对象

              2.1、通过ServletActionContext对象直接得到

                     ServletContextapplication = ServletActionContext.getServletContext();

                     HttpSessionsession = ServletActionContext.getRequest().getSession();

                     HttpServletRequestreq = ServletActionContext.getRequest();

                     HttpServletResponseres = ServletActionContext.getResponse();

              2.2、通过实现ServletRequestAware、ServletResponseAware、ServletContextAware接口,由struts2在运行时注入

文件上传:

       1、需要导入commons-uploadfile、commons.io包

       2、在form表单中使用post方法,并且声明enctype="multipart/format-data"属性

       3、定义的属性

              private File image; // 表示上传的文件

              private String imageFileName; // 表示上传文件的名称(约定大于规范,必须这样写)

              // setter和getter方法

              在action的方法中,把临时目录中的文件进行保存

              String realPath =ServletActionContext.getServletContext().getRealPath("/images");

              if(image != null){

                     FilesaveFile = new File(new File(realPath),imageFileName);

                     if(!saveFile.getParentFile().exists()){

                            saveFile.getParentFile().mkdir();

                     }

                     FileUtils.copyFile(image,saveFile);// 使用commons.io中的工具类完成拷贝

              }

       4、如果上传多个文件,客户端文件名称相同,服务器端则使用数组或List集合进行,如:

              private File[] images;

              private String[] imagesFileName;

              其他步骤同上

自定义拦截器:(实质是AOP的Around通知)

       要实现Interceptor接口的intercept方法即可。

       应用:

       1、在包中说明定义拦截器

       2、定义拦截器栈(必须包含系统定义的拦截器栈,必须在最前面,然后加上自己定义的拦截器)

       3、在action中引用自己定义的拦截器栈

       例如:

       <interceptors>

              <!-- 定义自己的拦截器 -->

              <interceptorname="permission"class="com.phome.interceptors.Permission"/>

              <!-- 定义拦截器栈(包含了系统定义的,并且是第一个) -->

              <interceptor-stackname="permissionStack">

                     <interceptor-refname="defaultStack"/>

                     <interceptor-refname="permission"/>

              </interceptor>

       </interceptors>

       ...

       <!--在action中引用自定义的拦截器栈 -->

       <action...>

              <interceptor-refname="permissionStack"/>

       </action>

       如果对包中的所有action都要进行拦截,在需要在包中定义引用的拦截器栈

       例如:

              <!-- 包级别的拦截器 -->

              <default-interceptor-refname="permissionStack"/>

       每个包只能指定一个默认的拦截器,每个action可以指定不同的拦截器,action的拦截器级别高。

输入校验:

       1、手动编写代码

              重写ActionSupport的validate方法即可完成对所有方法的输入验证,使用this.addFieldError("错误信息的关键字","错误信息")把错误信息添加到FieldErrors集合中,然后使用struts2的标签(<s:fielderror/>)在页面中显示错误信息。

              如果只校验某些方法,则使用validateXXX(其中XXX是方法名),这是“约定大于规范”的一个体现。

              例如:

                     publicvoid validateUpdate(){

                            if(this.userName == null ||this.userName.trim().equals("")){

                                   this.addFieldError("userNameNull","用户姓名不能为空!");

                            }

                            if(this.mobile == null ||this.mobile.trim().equals("")){

                                   this.addFieldError("mobileNull","手机号码不能为空!");  

                            }elseif(!Pattern.compile("^1[358]\\d{9}$").matcher(this.mobile).matches()){

                                   this.addFieldError("mobileFormatError","手机号码格式错误!");    

                            }

                     }

              在配置中提供input关键字对应的视图

              校验的流程:

                     1.1、类型转换器对请求参数进行类型转换,并把转换后的值赋给action中的属性,

                     1.2、如果转换过程中发生异常,则conversionError拦截器会把异常信息封装到fieldErrors中,进入下一步,

                     1.3、struts2会使用反射技术先调用validateXXX方法,最后才调用validate方法,

                     1.4、如果发现fieldErrors.size() > 0(有出错信息),在转发至input关键字对应的视图,没有错误,则进行action中的处理方法。

                     注意:

                            类型转换失败或校验失败均会进入到input关键字对应的视图中,注意区分。

       2、使用xml配置

              需要继承ActionSupport类,需要提供一个校验文件【action类名-validation.xml】,该校验文件必须和action类放在同一个包中。例如:

                     <validators>

                            <!-- 需要校验的字段 -->

                            <field name="userName">

                                   <!--指定一个系统已存在的校验器-->

                                   <field-validatortype="requiredstring">

                                          <!-- 为校验器注入一个属性值 -->

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

                                          <!-- 当校验失败时的提示信息 -->

                                          <message>用户姓名不能为空!</message>

                                   </field-validator>

                            </field>

                            <field name="mobile">

                                   <field-validatortype="requiredstring">

                                          <message>手机号码不能为空!</message>

                                   </field-validator>

                                   <!--指定一个系统已存在的正则表达式校验器 -->

                                   <field-validatortype="regex">

                                          <paramname="expression"><![CDATA[^1[358]\d{9}$]]></param>

                                          <message>手机号码格式错误!</message>

                                   </field-validator>

                            </field>

                     </validators>

              系统提供的校验器需要参考com.opensymphpny.xwork2.validator.validators.default.xml文件。

              如果想对action中的指定方法进行校验,需要提供一个校验文件【action类名-action类在struts.xml配置中的名称-validation.xml】,文件内容同上。

              例如:

                     在配置文件中:

                     <actionname="user_*" class="com.phome.UserAction"method="{1}">

                            ...

                     </action>

                     分析:

                            请求add()方法时,url为/person/user_add.action

                            namespace = /person

                            action名称 = user_add

                            action类名 = UserAction

                            所以,add方法的校验文件命名应该是:UserAction-user_add-validation.xml

                     如果存在所过方法的校验和某个方法的校验,则struts2会进行校验要求的合并,如果发生冲突,则使用后面文件的校验规则覆盖前面的。

                     如果存在action类的继承,则搜索校验文件的顺序是:父类的所有方法校验文件 --> 父类某个方法的校验文件 --> 子类的所有方法校验文件 --> 子类某个方法的校验文件,然后进行汇总校验。

struts2的国际化:(全局范围、包范围、action范围)

       1、全局范围的资源文件

              中文:资源文件的基名_zh_CN.properties

              英文:资源文件的基名_en_US.properties

              在struts2的配置中,添加<constant name="struts.custom.i18n.resource"value="资源文件的基名"/>即可

              然后就可以使用资源文件中的key进行访问:

                     在jsp页面中,使用<s:text name="键"/>进行访问

                     在action类中,继承ActionSupport类并使用其getText("键")进行访问

                     在表单标签中,使用<s:textfield key="键" .../>进行访问

              在资源文件中可以包含占位符(下标从0开始),如:{0}

                     在jsp页面中,使用如下格式进行访问

                            <s:text name="键"/>

                                   <s:param>第一个参数</s:param>

                                   <s:param>第二个参数</s:param>

                            </s:text>

                     在action类中,继承ActionSupport类并使用其getText("键",new String[]{"参数1","参数2"})进行访问

       2、包范围的资源文件

              在包中,必须以package_en_US.properties或package_zh_CN.properties方式命名,包及其子包都可以访问到该资源文件,如果查找一个key,则先到包范围内找,找不到才到全局范围中找

       3、action范围的资源文件

              针对某个action的专用资源文件,在action所在的包中,必须以action类名_en_US.properties或action类名_zh_CN.properties方式命名,如果查找一个key,则先到action范围内找,找不到再到包范围内找,还找不到才到全局范围中找

              可以通过<s:i18n>标签直接访问资源文件,而不需要任何配置

              例如:

                     <s:i18nname="资源文件的基名">

                            <s:text name="键"/>

                     </s:i18n>

                     或

                     <s:i18nname="路径/package"/>

                            <s:text name="键1"/>

                            <s:text name="键2">

                                   <param>参数</param>

                            </s:text>

                     </s:i18n>

                     或

                     <s:i18nname="路径/action类名"/>

                            <s:text name="键1"/>

                            <s:text name="键2">

                                   <param>参数</param>

                            </s:text>

                     </s:i18n>

OGNL(Object Graphic Navigation Language):对象图导航语言。

       OGNL的特点:

              1、支持对象方法的调用,如:xxx.sayHello()

              2、支持类静态方法的调用【 @类的完全限定名@方法名(参数)】,如:@java.lang.String@format('xxx%s','yyy')

              3、操作集合对象

       OGNL必须要和struts2的标签库的标签配合使用。

       OGNL上下文中包含了ValueStack、parameters、request、session、application、attr等对象,其中ValueStack是根对象,其中的对象可以直接访问,不需要使用#,ValueStack之外的容器中的对象访问时,需要使用#进行,每次一个请求,struts2都会创建一个新的ActionContext、ValueStack和action,然后把action放入ValueStack中,所以,在ValueStack中,可以直接访问action中的属性。

       访问OGNL根对象(ValueStack)中的对象的属性,除了使用OGNL外,还可以使用EL表达式直接访问。

       创建list对象:

              <s:set id="list"value="{'x','y','z'}" />

              <!-- list对象和ValueStack等对象属于同一个级别,但需要使用#访问 -->

              <s:iteratorvalue="#list">

                     <!--iterator在迭代集合时,会把当前迭代的对象放到ValueStack的栈顶,所以s:property不需要写value -->

                     <s:property/>

              </s:iterator>

       创建map对象:

              <s:set id="map"value="#{'key1':'value1','key2':90,'key3':'value3'}" />

              <s:iterator value="#map">

                     <!--StackValue的栈顶是当前迭代对象entry,entry对象有key和value属性 -->

                     <s:propertyvalue="key"/>=<s:property value="value"/>

              </s:iterator>

       投影产生子集合:

              集合对象.{子集合的描述}

              例如:

                     books.{?#this.price> 60} // 找出价格大于60的图书的子集合

                     其中:

                            ?表示条件

                            #this表示要进行迭代的books集合中的当前对象

Struts2标签:

       1、<s:property>:用于输出指定值。

              default:如果输入为null,则使用该缺省值

              escape:是否格式化HTML代码

              value:要输出的属性值或OGNL表达式,如果无该属性,默认输出ValueStack栈顶的值

       2、<s:iterator>:用于迭代

              value:被迭代的集合,如果无该属性,默认输出ValueStack栈顶的值

              status:迭代时,附加属性

                     intgetCount()、intgetIndex()、booleanisEven()、booleanisOdd()、booleanisFirst()、booleanisLast()

              例如:

                     <s:iteratorvalue="#list" status="st">

                            <font color=<s:iftest="#st.odd">red</s:if><s:else>blue</s:else>>

                                   <s:property/>

                            </font><br/>

                     </s:iterator>

              3、<s:if test="OGNL表达式">、<s:else>、<s:elseif test="OGNL表达式">

                     例如:

                            <s:set name="age"value="25" />

                            <s:if test="#age == 25">

                                   年龄是25

                            </s:if>

                            <s:else>

                                   年龄不是25

                            </s:else>

                     如果<s:set name="age"value="25" scope="request"/>,则访问时,必须是#request.age

              4、<s:url>:生成url,可以添加一个<s:param>参数标签

                     action:在struts.xml在action的名字

                     namespace:action所在的命名空间

                     例如:

                            <s:url action="abc_add"namespace="/test">

                                   <s:paramname="id" value="12"/>

                            </s:url>

                            生成的url为:项目名/test/abc_add.action?id=12

                           

                            %:当属性为字符串,而且是需要计算时,使用%

                            <s:set name="myurl"value="http://www.sina.com.cn"/>

                            <s:url value="#myurl"/><br/>                                                -->  输出#myurl

                            <s:url value="%{#myurl}"/><br/>                            --> 输出http://www.sina.com.cn

              5、复选框组标签:

                     list集合:<s:checkboxlistname="list" list="{'aa','bb','cc'}"value="{'aa'}"/>

                     map集合:<s:checkboxlistname="map" list="{1:'aa',2:'bb',3:'cc'}"listKey="key" listValue="value"value="{2,3}"/>

              6、默认主题:

                     在struts.xml在添加如下节点:

                     <constantname="struts.ui.theme" value="simple"/>后,则可以去掉struts标签生成的多余HTML标签

              7、单选框:

                     对象:<s:radio name="list"list="#request.persons" listKey="id"listValue="name"/>

                     list集合:<s:radio name="list"list="{'aa','bb','cc'}" value="aa"/>

                     map集合:<s:radio name="map"list="{1:'aa',2:'bb',3:'cc'}" listKey="key"listValue="value" value="2"/>

              8、使用<s:token/>防止表单重复提交

                     1、在表单中加入<s:token/>

                     2、在action配置中,引用系统提供的拦截器token,并添加<resultname="invalid.token"/>/输入页面</result>,注意不要忘了引用系统默认的拦截器

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值