Struts2 技术总结

来源:互联网 发布:华为5a切换数据流量 编辑:程序博客网 时间:2024/06/04 01:39

一、Struts环境搭建:

1、在http://struts.apache.org/download.cgi地址下载struts的所需资源。
2、在项目中导入所需jar包。为了方便以后的开发,可以把struts所需jar包封装成User Library 。方法自己找。
3、然后在web.xml文件中添加以下内容,也可以参考其它项目的web.xml文件
    <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>
4、在src目录下建立一个struts.xml,可以参考其它项目。
5、把User Library引入项目,否则会报错,方法自己找。(提示:项目->右键->properties->Deployment Assembly->add)

二、创建Action的三种方法

1、编写一个普通类,需要包含一个execute()方法,返回值为String,也可以在struts配置文件中注明方法名,不必包含execute()方法
2、实现Action接口,重写execute()方法。方法记得抛出异常
3、继承ActionSupport类,重写execute()方法。方法记得抛出异常

三、struts.xml文件解读

1、<constant name="struts.devMode" value="true" />  这句话的作用是允许修改完这个配置文件的内容可以不重启Tomcat,也能应用新配置。
2、<action name="hello" class="Action类的完整限定名">
            <result>
             /hello.jsp
            </result>
   </action>
    这个是配置文件的核心内容。
3、<constant name="struts.i18n.encoding" value="UTF-8" />    指定Struts的默认字符集类型。

四、Struts与MVC

1、一般MVC框架是使用M(模型层 javabean)、V(视图层 jsp或html)、C(控制层 Servlet) 。
2、Struts与MVC不同的地方在于控制层的组成,Struts的控制层由核心控制器(对应就是web.xml中的过滤器代码)和业务控制(对应的就是Struts.xml中的Action代码)来组成,核心控制器的作用是拦截web请求,而业务控制器的作用是把请求结果指向不同的视图页面。

五、Action类获取页面参数的方法

1、已属性方式接收用户表单参数:
(1)定义页面参数相应的属性,然后添加相应的geter和seter方法,注意属性名可以和页面元素的name不一样,但是get和set方法的名字一定要和页面的参数名字对应。
(2)Action指向的页面如果想获得该参数,则需要在html标签前引入以下内容:
<%@taglib uri="/struts-tags"  prefix="s"%>
然后在页面上就可以使用以下标签获得页面参数
<s: property value="参数名" />
2、使用javaBean获取用户表单参数
(1)建立表单元素对应的javaBean类。
(2)Action类中添加该javabean类的属性及其set和get方法。当然还是要添加execute方法。
(3)把表单对象中参数名修改为"Action中javaBean的属性名.字段名"
(4)其它用到这些参数的地方都需要按照第二点的要求来修改参数名
3、实现ModelDriven接口来获取用户表单参数
(1)建立表单元素对应的javaBean类
(2)建立一个Action类实现ModelDriven接口
(3)在Action类中添加javaBean对应的属性,并实例化(相当于第二种方法的set)
(4)重写ModelDriven接口的getModel()方法,返回值为javaBean类型,相当于第二种方法的geter。当然还是要添加execute方法。
(5)对于表单和其它页面,使用这些参数的时候直接使用参数名就可以(和第一种方法一样)。
上述三种方法之间的对比:
1、通过实现ModelDriven接口来接收参数的方法和使用javaBean方法的区别是,由于前者只提供了一个getModel方法用于返回实例,所以一个action只能对应一个model,而后者是通过get方法来获得对象,所以一个action可以对应多个model。
2、通过实现ModelDriven接口来接收参数的方法和通过属性接收参数的方法对比,这两种方法可以同时在一个Action中使用,在这种情况下,使用前者方式会优先赋值。

六、指定Action类中调用方法的三种方法(Action类中的execute方法不是必须的,可以使用以下方法定义别的方法。)

1、在struts配置文件的<action>节点中添加method属性。
<action name="login" class="action类的全限定名" method="action类中调用的方法名">
 <result>
   .........
 </result>
</action>
使用该方法可以实现使用一个Action类配置多个方法,然后在一个struts文件中使用多个action来指向这些方法,但是当Action中方法太多的时候,使用该方法就会显得结构不太清晰,这种情况下可以把这些action分散到不同的xml文件中,然后在struts文件中使用<include>来把这些包含进来,这样结构就可以比较清晰。实际开发都是使用这样的方法。例如:
新建一个user_add.xml,然后内容如下:
<package ...>
 <action ....>
 </action>
</package>
然后在struts配置文件中把上述文件包含进来,如下所示:
<struts>
 ......
 <include file="user_add.xml" />
</struts>
2、动态方法调用(该方法只需要搭建好struts的环境就可以使用)
此方法只需要添加一个<action>节点,也不需要使用method属性,只需要在请求地址中使用以下格式:
user!add  --->  <action名>!<需要调用的方法名>
可以在form表单的action中添加该地址,如下所示:
<form action="user!add" method="post">
.....
</form>
此方法的缺点是把Action的方法名暴露在地址中,可能造成安全隐患。
所以可以在struts中添加配置,禁止使用动态方法调用
 <constant name="struts.enable.DynamicMethodInvocation" value="false" />
3、使用通配符来实现方法调用
在<action>节点的name属性中可以使用一个或多个通配符,该通配符所代替的内容可以被多处引用,例如class,method或者是result中的地址,如下所示:
<action name="login_*_*" class="com.pb.web.{1}.{2}" method="{1}">
     <result>
 /{1}_{2}.jsp
     </result>
</action>
这样的话当碰到表单的action="login_user_add" 的时候,就会匹配到该<action>,然后{1}代表的内容是user,{2}代表的内容是add 。

七、Action匹配的优先级问题

1、优先使用完全匹配
2、如果没有完全匹配,再选择使用通配符的<action>
3、如果存在多个使用的通配符的<action>,则会根据先后顺序来选择使用
4、如果没有找到任何匹配的<action>,则会选择默认的action,需要配置默认action才能使用,配置如下:
<default-action-ref name="index">
<action name="index">
 <result>/index.jsp</result>
</action>

八、result的属性

1、name属性,该属性对应action类返回的字符串。默认值为"success",所以Action类返回success就能够跳转到指定视图。
2、type属性,该属性指定跳转的方式,常用的选项如下:
(1)dispatcher(默认)   使用转发的方式跳转,url地址不改变,可以传递表单参数,不能转发到别的Action(使用chain)
(2)redirect           使用重定向方式跳转,url地址改变,不可以传递参数,能重定向到别的Action
(3)redirectAction     重定向到指定的Action(本程序内部的Action)
(4)chain              Action链式处理,将Action转发到指定Action,需要指定nameSpace和Actionname参数
例如:
<result name="login" type="chain">
 <param name="namespace">/user</param>  (同一个包可以省略)
 <param name="actionName">login1</param>
</result>
(5)json               实现Ajax时返回Json对象
......
result跳转的视图一般采用绝对路径,在跳转到的视图页面前加"/"就是绝对路径,不加"/"就是相对路径,相对路径是相对于namespace的,而一般namespace都是根据包名来写,不一定有实际意义,所以最好使用绝对路径,以免找不到要跳转的页面。

九、全局结果

为了网页统一的效果,我们可以定义一下result,当action返回的字符串是指定的值时,统一跳转到指定页面,那样我们就可以使用全局的result,定义全局result之后,同一个包的action都能够使用这些result,等于在同一个包中的每个action中都添加了这些result,如果我们希望别的包也能够使用,那么可以让别的包继承该包。根据dtd文档可知,全局结果需要放在action之前,而且当全局结果和action中都有相同的result,那样action中的优先使用。
<global-results>
    <result name="error">/error</result>
    <result name="warn">/warn</result>
</global-results>

十、result动态结果

result的内容可以使用表达式或变量,称为动态结果,需要使用${"变量或表达式"} 。这个变量或表达式在action类里定义然后添加set和get方法就可以在result中使用。

十一、struts拓展

1、如果同一个包中有多个同名的action,则后面的会覆盖前面的。
2、包的namespace可以不配置,也可以取空值"",两者效果一样,只要action存在就可以访问到对应视图。但是当配置了namespace之后,访问访问action就必须加上namespace。
3、form表单的action应该取绝对路径,如果使用相对路径就会造成这样一个问题,当反复请求同一页面时,就会导致url的地址反复追加相对地址。如果form表单比较多,添加绝对路径比较麻烦的话,可以把绝对路径做成base路径,这样的话在同一个页面的form表单就可以使用相对路径,但是效果和绝对路径一样:在页面中添加如下代码:
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/" ;
%>
在head节点中加如下代码
<base href=<%=basePath%>>
4、struts的异常机制
(1)局部异常机制,该异常只在action内部有效,在action中定义。<exception-mapping>
(2)全局异常机制,该异常在整个包内都有效。<global-exception-mappings>
例如:
<global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>
其中exception代表异常类型的全限定名,result代表跳转到的action。

十二、使用ActionContext访问Servlet API的步骤

1、ActionContext ac = ActionContext.getContext(); // 首先获取ActionContext对象
2、Map<String,Object> request = Map<String,Object>ac.get("request"); //获得request的Map对象
3、Map<String,Object> session = ac.getSession();  //获得session对象
4、Map<String,Object> application = ac.getApplication(); //获得Application对象
5、request.put("loginAdress","你本次登录的地址:广州"); //利用request对象传递用户信息,因为是Map类型的数据,所以使用put来存、用get来取数据。
6、session.put("userName","XXX");//利用session对象传递用户信息
7、application.put("loginNum","当前登录的人次:XXX");//利用application对象传递用户信息
--------------------------------------------------------------------------------------------
在页面上读取数据推荐使用以下方法,里面的request、session、application是固定的,而且#也是必须的,使用attr可以取到前面三种对象的数据,但是实际开发不常用:
<s:property value="#request.loginAdress"/>
<s:property value="#session.userName"/>
<s:property value="#application.loginNum"/>
<s:property value="#attr.loginNum"/>
--------------------------------------------------
除了上述方法外还有两种方法可以访问这些对象:
1、使用JSP的内置对象方法<%=request.getAttribute("loginAdress")%>
2、EL表达式${request.loginAdress}
使用<s:debug/>可以查看有什么数据可以在页面使用。

十三、使用IcC方式获得Servlet API对象的步骤:

1、如果想获得request对象,只需要在Action类中实现对应的requestAware接口并实现其中的setRequest(Map<String,Object> request)方法即可,session和Application同理,对应有sessionAware接口和applicationAware接口,对应的方法是setSession(Map<String,Object> session)和setApplication(Map<String,Object> application),已request对象举例:
--------------------------------------------------------------------------------------
public class Action extends ActionSupport implements requestAware
public void setRequest(Map<String, Object> request) {
  this.request = request; 
 }
--------------------------------------------------------------------------------------
使用该方法我们可以不用管怎么获得request对象,struts已经帮我们在调用action时就处理好了。我们只管存取数据就可以。

十四、OGNL详解

1、OGNL全称:Object Graph Navigation Language 对象图导航语言,是struts2默认的表达式语言。
2、OGNL可以访问两类数据:Value Stack(Action中数据,例如Action的属性) 和 Stack Content(request、session、application等数据),前者可以直接访问,后者需要加"#"进行访问。例如:
<s:property value="username" />
<s:property value="#request.username" />
3、attr中包含有page、request、session、application中的属性,当使用<s:property value="#attr.username" />的时候,程序就会按照之前的顺序去寻找符合条件的元素,而且会返回第一个找到的元素。
4、OGNL访问List集合的元素和方法(相当于Action中的属性):
(1)<s:property value="ObjectList[0]" />的意思是访问集合ObjectList的第一个元素
(2)<s:property value="ObjectList.size()" />的意思是访问集合的size()方法,获得集合的大小。
(3)<s:property value="{1,2,3}" />的意思是构造集合。(不常用)
(3)<s:property value="{1,2,3}[0]" />的意思是访问构造集合的第一个元素。(不常用)
5、OGNL访问Map集合(相当于Action中的属性)
(1)<s:property value="ObjectMap['m1']" />或者<s:property value="ObjectMap.m1" />的意思是访问集合ObjectMap中键值为m1的值
(2)<s:property value="ObjectMap.size()" />的意思是访问集合的size()方法,获得集合的大小。
(3)<s:property value="#{'m1':'值1','m2':'值2'}" />的意思是构造集合。注意"#"和内容的写法(不常用)
(3)<s:property value="#{'m1':'值1','m2':'值2'}['m1']" />或者<s:property value="#{'m1':'值1','m2':'值2'}.m1" />的意思是访问构造集合的第一个元素。(不常用)
6、OGNL访问Set集合(相当于Action中的属性)
(1)<s:property value="ObjectSet.toArray()[0]" />的意思是访问集合ObjectSet的第一个元素,因为Set是无序集合,所以不能够直接通过索引来访问,需要先转换成数组才可以。
(2)<s:property value="ObjectSet.size()" />的意思是访问集合的size()方法,获得集合的大小。
7、OGNL访问静态方法和静态属性
(1)通过@类的完全限定名@静态方法名
(2)通过@类的完全限定名@静态属性名
注意:属性和方法的访问级别不能使用private
struts默认是不允许访问的静态方法和属性的,所以需要在struts的配置文件中添加如下配置:
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>

十五、Struts标签的分类

1、通用标签
注意:通过单引号''可以把OGNL对象转换成字符串对象,通过%{ }可以把字符串对象转换成OGNL对象
(1)数据标签
------------------------------------------------------------------------------------------
property  (用于显示OGNL表达式的内容)
value 指定显示内容的OGNL表达式
default value属性返回空值的时候,就会显示default的内容
escapeHtml 碰到HTML标签的时候,是否转义HTML,默认是"true",例如碰到"<"就会转义成 &lt;
------------------------------------------------------------------------------------------
date  (把指定的内容按照指定的日期格式显示)
name 指定需要转换成指定日期格式的内容,是一个OGNL表达式
format  指定日期的格式。比如 :yyyy-MM-dd HH:mm:ss
------------------------------------------------------------------------------------------
set  (把一个指定的内容设置成一个变量,可以允许别的标签引用)
var  需要设置成的变量名
value  需要设置成变量的内容
scope 变量的生存周期,默认是action,也可以是page,request,session,application,如果使用别的生存周期,注意使用变量的时候需要在相应的对象中取值   <s:property value="#session.s.username"/>
由于使用set设置的变量是放在Stack Context中,所以使用的时候需要在变量前加"#"
------------------------------------------------------------------------------------------
url  (用来生成一个url字符串)
var 该url的引用名。不使用该属性,该标签就会把字符串显示在页面上,加上这个属性页面上就不会显示,但是可以被其它标签引用,访问的时候需要在引用名前加"#" 。
action  指定要访问的action的名字
value  指定要访问的目标地址
------------------------------------------------------------------------------------------
a   (用来生成一个超链接)
href  用来定义超链接的url,可以使用<s:url>标签定义的变量
------------------------------------------------------------------------------------------
param (为其它标签添加参数,一般不会单独使用)
name  参数的名称
value  参数的值
例如:
<s:url var="t" value="t.jsp">
    <s:param name="username" var="zhangsan"></s:param>
</s:url>
相当于:
t.jsp?username=zhangsan
------------------------------------------------------------------------------------------
include  (把其它页面动态引入)
value 设置被引用的页面的url
------------------------------------------------------------------------------------------
(2)控制标签
<s:if>
<s:elseif>
<s:else>
test  表示是否符合条件,本身是一个OGNL表达式。
例如:
<s:if test="#status.odd">   其中#status.odd是一个OGNL表达式,值是布尔型。
------------------------------------------------------------------------------------------
<s:iterator>
<s:iterator var="house" value="ArrayStreet" status="status">
其中var表示每个迭代对象,存放在stack context中,所以使用时需要在前加"#",例如:#house
value表示需要迭代的集合对象
status表示集合的各种信息,包括当前对象的索引是基数或者偶数,存放在stack context中,所以使用时需要在前加"#" 。
status="st"
#st.index 可以取出当前循环的索引值
------------------------------------------------------------------------------------------
2、UI标签
模板和主题决定由struts标签生成的html页面的样式。每个标签都可以定义自己的theme属性。
<constant name="struts.ui.theme" value="simple"/>  可以通过该语句定义整个项目的主题
------------------------------------------------------------------------------------------
form  (能够生成html的form)
name  指定表单的名字,有时候不添加会报错,所以最好添加,而且不能是数字
action  指定要跳转的action或者页面
method 指定提交的方式
theme  指定表单的主题
....
------------------------------------------------------------------------------------------
textfield (相当于text输入框)
name  文本框的名字
value  设置文本框的默认值
....
------------------------------------------------------------------------------------------
textarea (相当于textarea多行文本框,区别:html中的textarea的默认值是设置在<textarea>默认值</textarea>中)
name 
value  多行文本框默认值
....
------------------------------------------------------------------------------------------
submit  (相当于提交按钮)
name
value 按钮的显示文本
....
------------------------------------------------------------------------------------------
select  (相当于html中的select)
name  下拉列表的名字
list  下拉列表显示的集合
listKey  相当于下拉列表选项的Value属性
listValue  相当于下拉列表选项的显示的文字
举例:
<s:select name="typeName" list="types" listKey="typeId" listValue="typeName"></s:select>
其中types是在Action 中定义的集合对象。可以使用<s:debug />来查看可用对象
------------------------------------------------------------------------------------------
doubleselect
name  与上同
list  与上同
listKey  与上同
listValue  与上同
doubleName  级联的下拉列表的名字
doubleList  级联的下拉列表显示的集合
doubleListKey  级联的下拉列表选项的Value属性
doubleListValue 级联的下拉列表选项的显示的文字
举例:
<s:doubleselect  name="dsitrict" list="ds.keySet()" listKey="strictId" listValue="strictName"
doubleName="street"  doubleList="ds.get(top)" doubleListKey="streetId" doubleListValue="streetName"
 ></s:doubleselect>
其中ds是一个Map<district,List<Street>> 对象,通过Map对象的keySet()方法可以获得district对象的集合,通过Map集合的get方法可以获得当前district对象对应的Street集合,top对象的作用就是指代当前选中的district对象
------------------------------------------------------------------------------------------
3、Ajax标签
使用Ajax标签之前需要导入对应的jar包(struts2-dojo-plugin-XXXX.jar)和Ajax标签库
<%@taglib uri="/struts-dojo-tags" prefix="sx" %>
------------------------------------------------------------------------------------------
datetimepicker  可以在页面上显示日历效果(使用该标签之前需要在head中添加语句<sx:head parseContent="true" />)
name 名称
label  用来设置组件前显示的文本

十六、如何在Action中获得struts页面元素的值

1、在Action中定义页面中与struts标签的name对应的属性,其实不一定要一致,但是由于需要生成set和get方法,而且这些方法名后面的名字要和页面元素对应的name值要一致,所以如果属性名一致的话就方便生成方法了。
2、生成这些属性的set和get方法。
3、利用这些属性获得页面标签的值。

十七、如何自定义标签主题

1、在struts的内置主题中找到对应的 *.ftl 文件 例如 div的对应的就是 div.ftl 。
2、把上述文件拷贝到自己项目的目录下 ,可以单独找个包放置,然后对文件进行修改。
3、然后在对应的标签中添加属性 theme="div" 这样就可以应用上自己定义的主题。

十八、提交表单之后,如果操作失败,如何做到数据回显

1、通过设置struts.xml的result 可以实现
2、使用type="chain" 可以实现转发方式跳转到别的action(对应注册页面提交的action,因为里面包含第一次提交时页面的参数),转发方式可以携带参数,所以可以实现回显。
3、注意有默认值的页面元素,回显时会显示默认值,所以如果想要正确回显,记得不要使用默认值。

十九、struts在服务器端验证表单信息的方法

1、在Action中编码实现表单验证 
(1)在Action的业务方法直接验证(业务方法默认是execute()) (需要继承ActionSupport,因为要使用该类的添加错误信息)
(2)重写validate()方法(需要继承ActionSupport,该Action所有的业务方法执行前都需要先调用此验证方法)
(2.1)当数据转换失败的时候也会执行该方法,例如年龄输入了字母,虽然我们在validate()方法中并没有检查该错误,但是该方法也会返回"input"和添加错误信息。并且所有业务方法都不会执行 。换种说法就是,该方法的执行不是我们能够控制的。我们只能够在里面添加我们需要验证的内容和添加错误信息。
(2.2)因为该方法是对所有的业务方法有效,所以所有针对这个Action的表单都要接受该方法的验证,因此该验证中只应该存在一些公共的验证,或者使用下面的有针对性的验证方法。
(3)使用validateXXX()方法。(需要继承,其中XXX代表的是业务方法的名字,所以使用该方法可以针对某个业务方法)
(3.1)例如针对login()这个业务方法,它对应的验证方法是validateLogin() 。只有当调用Action类中的login()方法的页面才会接受该方法的验证,其它页面不受影响。
(3.2)当validate()方法和validateXXX()方法同时存在时,两个方法都会起作用,validateXXX()先于validate()调用
----------------------------------------
添加错误信息的方法:
(1)字段错误  (this.)addFieldError(String FieldName,String errorMessage) 该类型的错误会在表单对应错误的位置显示错误信息,这就是为什么要填fieldName的原因
(2)Action错误   (this.)addActionError(String errorMessage)  该错误用于发生Action错误返回的信息,例如密码或用户名错误等!
(3)(this.)hasErrors() 可以判定是否存在上述两类错误,返回值是布尔型。
hasFieldErrors()   作用与上类似,但是只判断是否存在字段错误
hasActionErrors()  作用与上类似,但是只判断是否存在Action错误
----------------------------------------
在页面上显示错误信息
<s:fielderror fieldName="FieldName"/> 输出一个或所有的字段错误信息,如果指定fieldName,就只输出该字段的错误,否则显示全部字段错误。
<s:actionerror />  输出所有的Action错误信息
页面中判定是否存在错误使用以下两语句:
<s:if test="hasFieldErrors()" >
<s:if test="hasActionErrors()" >
注意:使用后两种验证方法(2)、(3),会在调用业务方法之前自动调用,一旦发现错误就会自动返回错误字符串"input" ,并且不会继续执行业务方法,所以必须添加一个<result>,其name="input" 的配置 。
2、使用验证框架实现验证
(1)在Action类的同目录下创建验证文件ActionName-validation.xml ,其中ActionName要与接受验证的Action一致。
(2)按照以下规则编写验证文件(可以查看帮助文档中的validation.html)
(2.1)验证文件的文件头如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
......验证器.....
</validators>
(2.2)验证器分为两种,一种是字段验证器,另外一种是非字段验证器
(2.3)字段验证器格式:
 <field name="user.userName">
      <field-validator type="requiredstring">
         <param name="trim">true</param>
          <message>You must enter a value for userName.</message>
      </field-validator>
      <field-validator type="stringlength">
          <param name="minLength">6</param>
          <param name="maxLength">10</param>
          <message>userName must be between ${minLength} and ${maxLength}, current value is ${user.userName}.</message>
      </field-validator>
 </field>
(2.3.1)对于同一个字段的验证器放置在<field></field>中,使用name属性指定是哪个字段。
(2.3.2)验证器使用<field-validator></field-validator>,其中type属性指定验证器的种类。
(2.3.3)错误信息使用<message></message>输出,该标签是必须的。
(2.4)非字段验证器格式:
<validator type="requiredstring">
    <param name="trim">true</param>
    <param name="fieldname">user.password</param>
    <message>You must enter a value for password</message>
</validator>
<validator type="stringlength">
     <param name="fieldname">user.password</param>
     <param name="minLength">6</param>
     <param name="maxLength">10</param>
     <message>password must be between ${minLength} and ${maxLength}, current value is ${user.password}</message>
</validator>
(3)针对某一个业务方法的验证文件
(3.1)、需要在sturts文件中定义一个<action name="login" class="com.pb.web.login" method="login">
(3.2)、然后在Action类的同目录下新建一个验证xml文件,命名为ActionName-alias-validation.xml  ,其中ActionName指action类名,alias是指定方法的action的name值,针对上面的action,alias就是指login 。
(3.3)、验证文件的规则与上同 。
(4)当actionName-validation和action-alias-validation文件同时存在,两个文件都会起作用。
(5)这两个文件作用的顺序是
Action父类-validation.xml
Action父类-alias-validation.xml
Action类-validation.xml
Action类-alias-validation.xml

二十、struts自带拦截器(部分)

1、params拦截器   将页面请求的参数设置成Action属性(Actin获得参数的第一种方式)
2、servletConfig拦截器  将Servlet API的各种对象注入Action
3、fileUpload  对文件上传提供支持
4、modelDriven  将getModel()中获得的结果压入Action值栈(Actin获得参数的第三种方式)
5、validation 调用验证框架进行数据验证
6、workflow 调用Action类的validate()执行数据验证
之前的学习中在struts.xml里我们没有配置拦截器,但是上述功能都能够实现,是因为我们的配置文件继承了默认的包struts-default,该包中包含了上述的拦截器配置,因此我们就可以使用这些拦截器。

二十一、struts.xml中配置拦截器(帮助文档是interceptor.html)

<package name="packName" extends="struts-default">
   <interceptors>
        <!--定义拦截器,其中name为拦截器名,class为拦截器使用的类的全限定名 -->
        <interceptor name="interceptorName"  class="interceptorClass"  />
 <!--定义拦截器栈  -->
        <interceptor-stack name="interceptorStackName" >
  <!--指定引用的拦截器,除了可以引用拦截器外,还可以引用别的拦截器栈 -->
  <interceptor-ref name="interceptorName|interceptorStackName" />
 </interceptor-stack>
   </interceptors>
   <!--定义默认的拦截器,如果Action中没有指定引用哪个拦截器,就会使用默认的拦截器,如果指定了,就会使用指定的拦截器,如果定义了默认拦截器,又想使用struts-default包的原来的默认拦截器,则需要在action中另外指定引用,可以指定引用多个拦截器  -->
    <!-- 注意默认拦截器是定义在独立的地方 -->
    <default-interceptor-ref name="interceptorName|interceptorStackName" />
    <action name="actionName" class="actionClass" >
    <!--为action指定拦截器引用 -->
         <interceptor-ref name="interceptorName|interceptorStackName" />
  <interceptor-ref name="interceptorName|interceptorStackName">
   <!--指定此过滤器不起作用的方法,可以没有这个参数,那就说明是所有方法都生效-->
  <param name="excludeMethods">login,register</param>
  <!--指定此过滤器起作用的方法,可以没有这个参数,那就说明是所有方法都生效-->
  <param name="includeMethods">login,register</param> 
  </interceptor-ref>
       <!--省略其它配置 -->
    </action>
</package>
小经验:1、拦截器栈定义中如果引用多个拦截器,则会按照先后顺序起作用
        2、Action对拦截器起作用的优先级是这样:如果Action中有引用拦截器,则会使用Action的拦截器,如果没有则会使用本包定义的默认拦截器,如果也没有,则会使用父包定义的默认拦截器。
二十、实现拦截器类的三种方法
1、实现Interceptor接口  ,实现该接口需要重写三个方法:
void init() 初始化拦截器中分配的资源
void destroy()释放在init()中分配的资源
String intercept(ActionInvocation ai) throws Exception  核心方法,定义在Action执行前后需要实现的功能
2、(推荐)继承AbstractInterceptor抽象类,只需要重写核心方法 String intercept(ActionInvocation ai) throws Exception  即可
3、继承MethodFilterInterceptor类 与上同,同时使用该方法还可以指定哪些方法需要拦截,哪些方法不需拦截。
小经验:通过ai.invoke()方法可以把处理交给下一个拦截器,如果没有后续拦截器则交给Acion,Action执行完之后就会反方向执行拦截器的后续代码,根据这个特点,应该是采用堆栈实现。


二十二、拦截器和过滤器异同

相同点
1、功能相同
2、原理相同
3、方法相似
拦截器1(过滤器1)<-->拦截器2(过滤器2)<-->拦截器3(过滤器3)<-->Action 
不同点
1、拦截器只能拦截action请求,而过滤器能够过滤几乎所有请求
2、拦截器在struts.xml中配置,而过滤器是在web.xml中配置
3、拦截器可以获得Action的当前执行状态等信息,而过滤器不能

二十三、struts框架实现单个文件上传功能

1、准备工作
(1)在项目中导入两个jar包:commons-fileupload-1.2.2.jar、commons-io-2.0.1.jar(在struts所需jar包中已包含)
(2)查看帮助文档初步了解。(file-upload.html)
(3)实现步骤:
(3.1)在JSP页面中实现让用户在客户端选择上传的文件
<s:form action="doUpload" method="post" enctype="multipart/form-data">
 <s:file name="upload" /><p />
 <s:submit />
</s:form>
注意以上代码中的enctype的内容是固定的写法,file中的name属性的值要和Action类中添加的File类型属性的名字一致。
(3.2)配置struts.xml,拦截器会自动上传选择的文件
说明:该部分的配置和普通的action配置一样,因为在继承的包struts-default中已经包含该功能所需要的拦截器配置,所以不需要另外添加拦截器
(3.3)在Action中写代码把上传的文件存入服务器
注意:
1、需要在Action中添加三个属性,及其set方法,注意这些属性的命名规则。
private File upload;  //该属性名字之所以要和上述file的name属性一致,目的是为了生成的set方法符合规则。(就是说可以不一致,但是set的方法就要另外写,不能使用生成)
private String uploadContentType;  //该属性的命名规则和上类似,ContentType前需要加file的名字,目的也是和上同
private String uploadFileName; //该属性的命名规则和上类似,FileName前需要加file的名字,目的也是和上同
2、设置好以上三个属性之后及其set方法后,struts就能够自动完成上传文件功能,该文件会保存成一个临时文件,通过输出upload属性可以看到其路径。,该文件会在Action结束后删除。
3、完成把临时文件保存到别的路径需要使用文件流:
String uploadpath = ServletActionContext.getServletContext().getRealPath("/upload/"+uploadFilename);
  FileInputStream fis = new FileInputStream(upload);
  FileOutputStream fos = new FileOutputStream(uploadpath);
  IOUtils.copy(fis, fos);   //使用IOUtils的copy方法可以完成文件复制
  fos.flush();
  fos.close();
  fis.close();
(3.4)跳转至新页面展示上传的文件
展示文件的方法可以使用文件保存路径加文件名的方法实现,文件名可以在值栈中找到:
<img alt="金莎" src="upload/<s:property value='uploadFilename'>" />

二十四、实现限制上传文件的类型和文件大小

1、注意:struts默认上传的文件大小限制为2M,如果需要修改的话可以使用以下方法:
在struts.xml中添加以下语句:
<constant name="struts.multipart.maxSize" value="1000000"/>
通过添加以下常量,可以把大小限制值修改为1000000字节,约等于10M 。
注意以上配置是对整个项目都有效,如果只想要限制某个Action的文件上传大小,可以使用以下语句,该语句放在对应Action的fileupload拦截器中,如下所示:
<action name="actionName" class="actionClass">
 <interceptor-ref name="fileUpload">
  <param name="maximumSize">30000</param>
 </interceptor-ref>
 <interceptor-ref name="defaultStack"></interceptor-ref>
</action>
2、限制上传文件的类型使用以下语句,类型之间用","隔开,注意类型的写法(后缀名对应的写法可以查询项目Servers中的Tomcat下的web.xml):
<action name="actionName" class="actionClass">
 <interceptor-ref name="fileUpload">
  <param name="allowedTypes">imgge/pjpeg,image/jpeg</param>
 </interceptor-ref>
 <interceptor-ref name="defaultStack"></interceptor-ref>
</action>


二十五、实现上传多个文件步骤:

1、在客户端需要选择多个文件
--> 该步可以通过添加多个<s:file name="fileName" />标签实现,其中fileName都要一致。
2、Action类中需要自动上传多个文件。在单个文件的基础上把以下方法的返回类型改为集合类型,相应的set方法也要修改
private List<File> upload;  //该属性名字之所以要和上述file的name属性一致,目的是为了生成的set方法符合规则。(就是说可以不一致,但是set的方法就要另外写,不能使用生成)
private List<String> uploadContentType;  //该属性的命名规则和上类似,ContentType前需要加file的名字,目的也是和上同
private List<String> uploadFileName; //该属性的命名规则和上类似,FileName前需要加file的名字,目的也是和上同
3、把上传的多个文件都存入服务器。然后使用循环把多个文件都进行保存。
for(int i=0;i<upload.size();i++){
 String uploadpath = ServletActionContext.getServletContext().getRealPath("/upload/"+uploadFilename.get(i));
 FileInputStream fis = new FileInputStream(upload.get(i));
 FileOutputStream fos = new FileOutputStream(uploadpath);
 IOUtils.copy(fis, fos);
 fos.flush();
 fos.close();
 fis.close();
}
4、跳转至新页面展示上传的所有文件。

二十六、java实现国际化的步骤

1、准备资源文件,资源文件有以下特点:
(1)存放在src根目录下,一般和struts存放在同一目录。
(2)资源文件的命名规则:前缀_语言代码_国家代码.properties,例如:message_zh_CN.properties。需要注意的是还有一个特殊的资源文件,当找不到指定的资源文件时,该文件就会生效,该文件的命名规则:前缀.properties,例如:message.properties
(3)资源文件的内容一般是这样的结构:key = value
2、获取国际化信息的两种方法
(2.1)使用java代码获取国际化信息
(1)指定语言  Locale locale = Locale.SIMPLIFIED_CHINESE;
(2)获取指定语言的资源文件 ResourceBundle bundle = ResourceBundle.getBundle("资源文件前缀(message)",locale);
(3)获取指定的资源信息(返回key对应的value)  String bundle.getString("key")
(2.2)使用struts标签在jsp页面中获取国际化信息
(1)指定资源文件 ,通过在struts.xml添加常量指定<constant name="struts.custom.i18n.resources" value="资源文件前缀(message)"/>或者在struts.properties中添加配置struts.custom.i18n.resources=资源文件前缀(message)
(2)页面输出国际化信息  <s:text name="key" />  ;如果需要输出带参的国际化信息,需要使用<param>传递参数,代码如下:
<s:text name="key">
   <s:param>username</s:param>
</s:text>
(3)针对UI标签可以使用key属性输出国际化信息 <s:textfield key="key">,这个key属性的作用相当于原来的label属性,不过这个可以用于输出国际化信息。注意UI标签的主题不能使用simple,一般使用xhtml ,否则没有国际化效果。
强调:UI标签不支持传递参数的国际化信息。
(2.3)使用struts在Action类中返回国际化信息
(1)继承ActionSupport类可以使用该类的getText(String key)方法和getText(String key,String[] args)方法,这两个方法都可以获取国际化信息,后一个方法还可以传递参数。使用传递参数的方法之前,需要修改资源文件内容如下:
welcome = {0}欢迎!
在原来的value前添加{0}占位符 就可以实现传递参数的国际化信息 。可以在不同位置添加多个参数{}中的内容是字符串参数数组的下标
(2)例如我们可以把添加字段错误信息实现国际化 addFieldError("username",getText("key"));
(3)我们也可以在登录成功的时候把带有参数(例如用户名)的欢迎信息返回到页面 addActionMessage(getText("key",new String[]{username}));

二十七、资源文件按有效范围的分类

1、类级资源文件,是针对某个Action类起作用的资源文件,需要和该Action类放在同一个目录,命名规则:Action类名_语言代码_国家代码.properties  。优先级最高
2、包级资源文件  是针对某个包起作用的资源文件,需要在该包的目录下,命名规则:package_语言代码_国家代码.properties 。优先级次之 。
3、全局级的资源文件  二十四点的内容就是指全局的资源文件。优先级最低。
4、使用<s:i18n name="资源文件前缀">....</s:i18n>,可以指定该标签范围内所使用的资源文件。

二十八、Json与javascript

1、javascript如何创建json对象
var user = {"int":1,"name":"admin","grade":null};
2、javascript如何访问json的值
var name=user.name;
3、json对象与字符串之间的转换
json对象转换为字符串:  var str=JSON.stringify(user); --> 转换之后格式 '{"int":1,"name":"admin","grade":null}'
字符串转换为json对象:  var json =JSON.parse(str);
4、jquery插件安装
在eclipse的安装路径下建立一个links文件夹(eclipse/links),然后把spket-1.6.23文件夹复制到links文件夹中,启动eclipse,然后打开window->preferences-spket->javascript profiles ,然后点击New,起个名字,然后点击default,把新建的profile设置成默认,点击add Library,选择jquery,点击ok,继续选择add File ,选择jquery库(jquery-1.8.2.js),完成设置。
5、如何编写一段javascript在页面加载时自动执行
$(document).ready(function(){......})
6、javascript定义数组
var ary =["a","b","c"];
7、javascript定义json数组
var users=[{"int":1,"name":"admin","grade":null},{"int":1,"name":"admin","grade":null},{"int":1,"name":"admin","grade":null}];


二十九、使用struts实现Ajax的方法

1、在项目中添加两个jar包,json-lib-xx-jdk15.jar 和 struts2-json-plugin-xxx.jar
2、修改struts.xml文件,把package继承的包修改为"json-default" 。
3、result中的type属性修改为"json" 。同时还可以使用<param name="includeproperties">user.*,....</param>来限定json中返回那些值,不加该参数就返回所有Action属性。
4、在页面使用jquery实现Ajax请求。jQuery对Ajax进行了封装,使用$.ajax(content)就可以发送Ajax请求和接收返回数据,以下代码可以放在按钮的click事件或以其它方式触发:
$.ajax({
    url:"getData", //请求的url地址,可以是Action的name
    type:"POST",  //请求的方式,默认是get
    data:{"name":"admin","password":"12345"},   //发送到服务器的参数,使用json格式,可以使用null
    dataType:"json",  返回数据的格式
    success:function(data){....},  //请求数据成功后进行的操作,data中可以获取请求回来的数据,包括Action的属性
    error:function(data){.....}  //请求失败做的操作
});