文档库 最新最全的文档下载
当前位置:文档库 › Struts2

Struts2

一.搭建Struts2的开发环境:
1.添加jar包
2.在web.xml中配置struts的过滤器
3.在根目录下添加一个一个struts.xml文件


二.package

1.package:struts2使用package来组装模块
https://www.wendangku.net/doc/513587370.html,属性:必选项,用于其他包引用当前包
3.extends属性:当前包继承那个包,可以继承父包中的所有的配置,通常情况下继承struts-default
https://www.wendangku.net/doc/513587370.html,space:该属性是可选的,如果没有给出,则以"/"为默认值,若namespace有一个非默认值,则想要调用这个包里的Action,
则必须把这个属性所定义的命名空间添加到有关的URI字符串里。
eg:http://localhost:8080/contextPath/namespace/actionName.action


三.action:代表一个Struts2的请求

/WEB-INF/pages/add.jsp

以上的代码是配置一个action(一个struts2的请求就是一个action)
1.action中的name:对应一个struts2的请求的名字(或对应一个servletPath,但去除/和扩展名),不包含扩展名。
2.class:处理该请求的类,默认为ActionSupport类。
3.method:处理该请求的类中的方法,默认的方法为execute()方法.
4.result中的name:处理该请求的方法的返回值,默认值为"success"。
多个result子节点使用name区分。
5.result中的type:表示结果的类型,默认值为dispatcher(转发到结果)。
6.result标签的内容:该请求的下一个Action或显示页面。


四.Action是能够处理Struts2请求的类
1.属性的名字必须遵守与JavaBean的属性名相同的命名规则。属性的类型可以使任意类型,
从字符串到非字符串(基本数据库类型)之间的数据转换可以自动发生。
2.必须有一个不带参的构造器,通过反射创建实例。
3.至少有一个struts在执行这个Action时调用的方法,同一个Action可以包含多个action方法。
4.Struts2会为每一个HTTP请求创建一个新的Action实例,即Action不是单例的,是线程安全的。


五.在Action中访问WEB资源
1.什么是WEB资源:HttpServletRequest,HttpSession,ServletContext等原生的Servlet API.
2.问什么访问WEB资源:B\S的应用的Controller中必然需要访问WEB资源:向域对象中读写属性,读写cookie,获取realPath。
3.如何访问:
1).和Servlet API解耦的方式:只能访问优先的Servlet API对象,且只能访问有限的方法(读取请求参数。读取域对象的属相,是session失效)。
(1).使用ActionContext对象:
ActionContext actionContext = ActionContext.getContext();
ActionContext是Action执行的上下文对象,在ActionContext中保存了Action执行所需的所有对象,
包括parameters,request,session,application等。
①.获取HttpSes

sion对应的Map对象: public Map getSession()
eg:Map sessionMap = actionContext.getSession();
sessionMap.put("sessionKey", "sessionValue");
②.获取Application对应的Map对象:public Map getApplication()
eg:Map application = actionContext.getApplication();
//设置属性
application.put("applicationKey", "applicationValue");
//获取属性
System.out.println(application.get("date"));
③.获取请求参数(parameters)对应的Map对象: public Map getParameters()
eg://获取请求参数(parameters)对应的Map,并获取指定的参数值
//键:请求参数的名字 值:请求参数对应的字符串数组
//注意:1.getParameters的返回值为Map,而不是Map
// 2.parameters这个Map只能读,不能写入,如果写入,不会出错,但也不起作用。

Map parametersMap = actionContext.getParameters();
System.out.println(((String[])parametersMap.get("name"))[0]);
parametersMap.put("parametersKey", "parametersValue");
④.获取HttpServletRequest对应的Map对象: public Object get(Object key):ActionContext类正没有提供类似getRequest()这样的方法来获取HttpServletRequest对应的Map对象,
eg://ActionContext并没有提供对应的getRequest()方法来获取request对应的Map
//需要手工调用get()方法,并传入request字符串作为参数
Map requestMap = (Map) actionContext.get("request");
requestMap.put("requestKey", "requestValue");
(2).实现XxxAware接口:
具体实现见ex2.TestAwareAction.java
eg:
private Map parametersMap ;
private Map requestMap;
private Map sessionMap;
private Map applicationMap;
public TestAwareAction() {
// TODO Auto-generated constructor stub
}
@Override
public void setParameters(Map arg0) {
this.parametersMap = arg0;
}

@Override
public void setRequest(Map arg0) {
this.requestMap = arg0;
}

@Override
public void setSession(Map arg0) {
this.sessionMap = arg0;
}

@Override
public void setApplication(Map arg0) {
this.applicationMap = arg0;
}
(3).选用建议:若一个Action中有多个action方法,且多个方法都需要使用域对象的Map或parameters,则建议使用实现XxxAware接口的方式。
(4).session对应的Map实际上是SessionMap类型,强转后调用invalidate()方法,可以使其session失效。
即:(SessionMap)sessionMap.invalidate();
2).和Servlet API耦合的方式:可以访问更多的Servlet API对象,并且

可以调用其原生的方法。
(1).使用ServletActionContext:
ServletActionContext:可以从中获取当前Action对象需要的一切与Servlet API相关的对象。
常用的方法:
①.获取HttpServletRequest对象:ServletActionContext.getRequest();
②.获取HttpSession对象:通过获得的request对象调用getSession()方法得到session对象。
即:HttpSession session = ServletActionContext.getRequest().getSession();
③.获取ServletContext对象:ServletActionContext.getServletContext();
(2).实现ServletXxxAware接口:有Struts2注入需要的Servlet相关的对象
①.ServletRequestAware接口:注入HttpServletRequest对象
②.ServletContextAware接口:注入ServletContext对象
③.ServletResponseAware接口:注入HttpServletResponse对象


六.ActionSupport类
1.Actionupport是默认的类,若某个action节点没有配置class属性,则ActionSupport即为待执行的Action类,而execute方法即为默认执行的action方法。
2.在手工完成字段验证,显示错误消息,国际化等情况下,推荐继承ActionSupport类。


七.result节点
1.result是action节点的子节点。
2.result代表action方法执行后,可能去的目的地。
3.一个action节点可以配置多个result子节点
4.result的name属相值对应着action方法 可能有的返回值。
5.result的type属性:表示结果的响应 类型
6.result的type属性值在struts-default包的result-types节点的name属性中定义,常用的有:
①.dispatcher(默认的):转发
eg:/WEB-INF/pages/ex3/dispatcher.jsp
②redirect:重定向
eg:/redirect.jsp
③redirectAction:重定向到一个Action
eg:

testResultAction_Redirect
/testResultAction

OR
/testResultAction/testResultAction_Redirect.do
④chain:转发到一个Action
eg:
只能是:

testResultAction_Chain
/testResultAction

不能是:
/testResultAction/testResultAction_Chain.do


八.通配符的匹配:
1.通配符映射规则:
①.若找到多个匹配,没有通配符的将优先匹配
②.若指定的action不存在,Struts将会尝试把这个URI与任何一个包含通配符*的action进行匹配。
③.被通配符匹配到的URI字符串可以用{1},{2}来引用,{1}匹配第一个字串,{2}匹配第二个字串...
eg:

/WEB-INF/pages/{1}.jsp
<

/action>
④.{0}匹配整个URI
⑤.若Struts找到带有通配符的匹配不止一个,则按先后顺序进行匹配。
⑥.*可以匹配零个或多个字符,但不包括/字符,如果想把/字符包括在内,需要使用**,如果需要对某个字符进行转义,需要使用\。
eg:

/WEB-INF/pages/ex4/{1}.jsp



九.动态方法调用:
打开允许动态方法调用的开关,默认的情况下是FALSE

通过URL动态调用Action中的方法
eg:下面的URL默认调用execute方法:
http://localhost:8080/Struts2_2/testDynamicMethodInvocation.action
我们可以采用动态方法调用是该URL调用save方法:
http://localhost:8080/Struts2_2/testDynamicMethodInvocation!save.action


十.OGNL标签
1.值栈:贯穿整个Action的生命周期(每个Action类的对象实例都拥有一个ValueStack对象).相当于
一个数据的中转站,在其中保存当前Action对象和其他相关对象。Struts框架把ValueStack
对象保存在名为"struts.valueStack"的请求属性。
1).在ValueStack对象的内部有两个逻辑部分:
(1).ObjectStack:实际上是CompoundRoot类型,是一个使用ArrayList定义的栈,是一个实际意义上的栈。
struts把Action和相关对象压入ObjectStack中。
(2).ContextMap:Struts把各种各样的映射关系(一些Map类型的对象)压入ContextMap中,实际上就是对ActionContext的一个引用。
2).Struts会把下面的这些映射压入ContextMap中
(1).parameters:该Map中包含当前请求中的所有属性
(2).request:该Map中包含当前request对象中所有属性
(3).session:该Map中包含当前session对象中所有属性
(4).application:该Map中包含当前application对象中所有属性
(5).attr:该Map按request,session,application顺序检索某个属性
3).值栈中的属性值:
1).对于ObjectStack :对象栈中某一个对象的属性值。
2).ContextMap栈:request,session,application中的一个属性值或一个请求参数值。
4).Struts2自动把Action对象放入到值栈中:
1).放入的时间点:Struts2终将调用Action类的action方法,但在调用该方法之前:
->先创建一个StrutsActionProxy对象
->在创建strutsActionProxy之后,对其进行初始化的时候,把Action放入到值栈中。
2.OGNL:在JSP页面上可以利用OGNL(Object-Graph Navigation Language:对象-图导航语言)访问到值栈里的对象属性。
如果希望访问值栈中ContextMap中的数据,需要给OGNL表达式加上一个前缀字符#,如果没有前缀字符#,搜索将在ObjectStack里进行。
3.利用OGNL读取值栈中的对象的属性值
1).Struts2利用s:property 标签和OG

NL表达式读取值栈中的属性值
2).读取ObjectStack里的某个对象的属性,可以使用以下几种方式:
(1).object.propertyName
(2).object['propertyName']
(3).object["propertyName"]
3).ObjectStack里的对象可以通过一个从零开始的下标来引用。
ObjectStack里的栈顶对象可以用[0]来引用,它下面的那个对象可以用[1]引用,
若希望返回栈顶对象的message属性值:[0].message或[0]["message"]或[0]['message']
4).若指定的对象里没有找到指定的属性,则到指定对象的下一个对象里继续搜索,即[n]的含义是从第n个开始搜索,而不是只搜索第n个对象。
5).若是从栈顶对象开始搜索,可以省略下标部分。
eg: 等同于
property标签的属性
名字 类型 默认值 说明
default String 可选,如果value值为null,或没有指定,将显示该属性值
escape Boolean true 可选,是否要对HTML特殊字符进行转义
value String <来自栈顶对象> 将要显示的值
4.读取ContextMap里的对象的属性
1).读取ContextMap里的某个对象的属性,可以使用以下几种方式:
(1).#object.propertyName
(2).#object['propertyName']
(3).#object["propertyName"]
eg:返回session中的code属性:#session.code
返回request中的customer属性的name属性值:#https://www.wendangku.net/doc/513587370.html,
返回域对象(按request,session,application的顺序)的lastAccessDate属性:#https://www.wendangku.net/doc/513587370.html,stAccessDate
5.OGNL调用字段和方法:
1).利用OGNL可以调用:
(1).任何一个Java类里的静态字段和方法。
(2).被压入到ValueStack栈的对象上的公共字段和方法
2).默认情况下,Struts2不允许调用任意Java类静态方法,需要重新设置
struts.ognl.allowStaticMethodAccess标记变量的值为true。
3).调用静态字段和或方法需要使用如下所示的语法:
(1).@fullQualifiedClassName@fieldName:
eg:@java.util.Calendar@DECEMBER
(2).@fullQualifiedClassName@methodName(arguments):
eg:@app4.Util@now()
4).调用一个实例字段或方法的语法,其中object是ObjectStack栈里的某个对象的引用
(1).object.fieldName
eg:[0].dataPattern
(2).object.methodName(argumentList)
eg:[0].repeat(3,"hello");
6.利用OGNL访问数组类型的属性
1).有些属性将返回一个对象数组而不是单个对象,可以像读取任何其他对象属性那样读取它们,
这种数组型属性的各个元素以逗号分隔,并且不带方括号
2).可以使用下标访问数组中指定的元素,
3).可以通过调用其length字段查出给定数组中有多少个元素
eg:
array数组的长度Length:


array数组

的第二元素array[1]:
7.利用OGNL访问List类型的属性
(1).有些属性将返回的类型是java.util.List,可以像读取任何其他属性那样读取它们,
这种List的各个元素是字符串,以逗号分隔,并且带方括号
(2).可以使用下标访问List中指定的元素
(3).可以通过调用其size()方法或专用关键字size的方法查出给定List的长度:color.size或color.size()
(4).可以通过使用isEmpty()方法或专用关键字isEmpty来得知给定的List是不是空
(5).还可以使用OGNL表达式来创建List,创建一个List与声明一个Java数组是相同的:{"Red","Green","Black"}
eg:
List的长度:


List的第二个元素:
8.利用OGNL访问Map类型的属性
(1).读取一个Map类型的属性将以如下所示的格式返回它们所有的键值对:
{key_1=value_1,key_2=value_2,...,key_n=value_n }
(2).若希望检索出某个Map的值,需呀使用如下格式:map[key]
(3).可以使用size或size()得出某个给定的Map的键值对的个数
(4).可以使用isEmpty或isEmpty()检索出给定的Map是不是空
(5).可以使用如下语法来创建一个Map
#{key_1=value_1,key_2=value_2,...,key_n=value_n}
eg:
map集合的键值对的个数:


Map几个的第二对键值对的值:
9.使用EL访问值栈中对象的属性
1).也可以通过JSP EL表达式来达到目的:${fieldName}
2).原理:Struts2将包装HttpServletRequest对象后的org.apache.struts2.dispatcher.StrutsRequestWrapper
对象传到页面上,而这个类重写了getAttribute()方法。
10.异常处理exception-mapping元素
1).exception-mapping元素:配置当前action的声明式异常
2).exception-mapping元素中有两个属性
(1).exception:指定需要捕获的异常类型,异常的全类名。
(2).result:指定一个响应结果,该结果将在捕获到指定异常时被执行,既可以来自当前action的声明,也可以来自global-results声明.
eg:


/exception.jsp
/details.jsp

3).可以通过global-exception-mappings元素为应用程序提供一个全局性的异常捕获映射,但在global-exception-mappings元素下声明
的任何exception-mapping元素只能引用在global-results元素下声明的某个result元素。
eg:

/exception




4).声明式异常处理机制有ExcetionMappingInterceptor拦截器负责处理,当某个exception-mapping元素声明的异常被捕获到时,
ExceptionMappingInterceptor拦截器就会向ValueStack中添加两个对象:
(1).exception:表示被捕获异常的Exception对象
eg:
(2).exceptionStack:包含着被捕获异常的栈
eg:


十一.通用标签
1.标签:打印值栈中的属性值的:
1).对于对象栈:打印值栈中对应的属性值:
2).对于Map栈:打印request,session,application的某个属性值或某个请求参数的值
2.:动态的创建一个URL
url标签的属性:
名字 类型 默认值 说明
action String 可选,指定生成的URL为哪个action
includeParams String get 可选,指定是否包含请求参数,可以取3个值之一:none,get,all
method String 可选,指定action的方法,当前action属性未生成URL时,如果指定该属性,将链接到指定的action的方法上
namespace String 可选,指定URL的命名空间
value String 可选,指定将生成的URL的值(如果新建的URL不是一个action的话)
var String 可选,指定用来被压入ContextMap中的键值
eg:
1).简单的URL字符串:





//结果:/Struts2_3/getUrl1?productName=1002
2).对value值会自动进行OGNL解析:




${url2 }
//结果: /Struts2_3/getUrl2?productName=Computer
3).对value值会自动进行OGNL解析,但不希望自动解析,使用单引号引起来:





//结果:/Struts2_3/getUrl3?productName=productName
4).创建一个请求Action的URL:



//结果: /Struts2_3/ognl/testTag!testTag.action
5). 创建一个可以接受请求参数的URL:

ams="all">
zhangsan

${url5 }
//结果:getUrl5?name=testTagByJxust¶m=zhangsan
6). 把一个EL表达式作为参数的value值:

${productName }

${url6 }
//结果: /Struts2_3/getUrl6?ELExpression=Computer
3.:把一个参数传递给包含着它的那个标签
1).param标签的属性:
名字 类型 默认值 说明
name String 将传递给外层标签的参数的名字
value String 将传递给外层标签的参数的值
2).无论在给出的value值时有没有使用%{},Struts都会对它进行OGNL求值
eg:
3).如果想传递一个String类型的字符串作为参数值,必须把它用单引号括起来
eg:
4).可以把value属性的值写在开始标签和结束标签之间,利用这种方式来传第一个EL表达式的值
eg:${productName }
5).从ContextMap栈中读取值作为参数
eg:
4.标签:用来在以下的Map对象里创建一个键值对:
->ValueStack值栈的ContextMap值栈
->Map类型的session对象
->Map类型的application对象
->Map类型的request对象
->Map类型page对象
set标签的属性
名字 类型 默认值 说明
name String 将被创建的属性的键
value String 该键所引用的对象
scope String default 目标变量的作用范围,可取值是application,session,reqeuest,page和default
eg:
利用set标签把一个对象放入request域对象中:



5.push标签
1).功能:和set标签的功能相似
2).push标签将把一个对象压入ValueStack而不是压入ContextMap
3).push标签在标签起始时把一个对象压入栈,标签结束时将对象弹出栈。
eg:
s:push:push标签在标签起始时把一个对象压入栈,标签结束时将对象弹出栈:
<%
Person person = new Person();
person.setName("pushTest");
person.setAge(10);
request.setAttribute("person", person);
%>

${name }

//结果:pushTest
6.if,else和elseif标签
eg:

I7处理器


I5处理器


I3处理器



Person的age:

大于20岁



大于10岁


小于10岁或等于10岁

7.iterator标签:
1). iterator标签用来遍历一个数组,Collection或一个Map,并把这个可遍历对象里的每一个元素一次压入和弹出ValueStack栈
2). iterator标签的属性
名字 类型 默认值 说明
value String 将被遍历的可遍历对象
status org.apache.struts2.views.jsp.InteratorStatus
var String 用来引用这和可遍历对象那个中的当前元素的变量
3).在开始执行时,iterator标签会先把IteratorStatus类的一个实例压入ContextMap,并在每次遍历循环是更新它,
可以将一个执行 IteratorStatus对象的变量赋给status属性。
eg:
Iterator遍历ContextMap中的对象的属性值:
    

index:${status.index }--count:${status.count }--${name }--${age }
    

Iterator遍历ObjectStack中的属性值:
    

index:${status1.index }--count:${status1.count }--${name }--${age }
    

8.s:sort标签:
1).功能:用来对一个可遍历对象里的元素进行排序
2).sort标签的属性
名字 类型 默认值 说明
comparator https://www.wendangku.net/doc/513587370.html,parator 在排序过程中使用的比较器
source String 将对之进行排序的可遍历对象
var String 用来引用因排序而新生成的可遍历对象的变量
eg:



index:${status.index }--count:${status.count }--${name }--${age }
    

9.s:date标签:
1).功能:用来对Date对象那个进行排版
名字 类型 默认值 说明
format String 可选,日期的格式
name String 将被排版的日期值
nice boolean false 可选,指定是否输出指定日期和当前日期之间的时间差
id String 可选,用来引用被压入ValueStack栈的日期值的变量
2).format属性的值必须是java.text.SimlpeDateFormat类里定义的日期/时间格式之一。
eg:

${date2 }
10.s:a标签:将呈现为一个HTML链接,这个标签可以接受HTML语言中的a元素所能接受的所有属性
eg:


${name }   

11.action标


1).功能:用来在页面上执行一个action
2).还会把当前Action对象压入ValueStack值栈的ContextMap子栈
名字 类型 默认值 说明
executeResult Boolean FALSE 是否执行/呈现action的结果
flush Boolean TRUE 是否要在动作结束后对"写"缓冲区进行"冲洗"
IgnoreContextParams boolean FALSE 是否要在触发该action时2把请求参数包括进来
name String 将要触发的action的名字,不需要.action后缀
namespace Boolean 与当前标签使用的相同 将要触发的action的命名空间
var String 用来引用被压入ContextMap栈的动作对象的变量
12.bean标签:将创建一个JavaBean,并把它压入ValueStack值栈的ContextMap子栈,这个标签的功能与JSP的useBean动作元素很相似
名字 类型 默认值 说明
name String 将创建的JavaBean的完全类名
var String 用来引用被压入ContextMap栈的JavaBean的变量
13.include标签:用来把一个Servlet或JSP页面的输出包含到当前页面里来。
名字 类型 默认值 说明
Value String 将被包括的Servlet/JSP页面的名字


十二.表单标签
1.特点:
1).使用和HTML的form标签柑橘差不多
2).Struts2的form标签会生成一个table,以进行自动的排版
3).可以对表单提交的值进行回显:从ObjectStack的栈顶对象开始匹配属性,并将匹配的属性值赋给到对应的标签的value属性中,
若栈顶对象没有找到对应的属性,则依次向下找对应的属性。
2.表单标签的共同属性
名字 数据类型 说明
cssClass String 用来显示这个元素的CSS类
cssStyle String 用来呈现这个元素的CSS样式
title String 指定HTML title属性
disable String 指定HTML disabled属性
*label^ String 指定一个表单元素在xhtal和Ajax主题里的行标
labelPosition String 指定一个表单元素在xhtal和Ajax主题里的行标位置,可取值时top和left(默认值)
key String 这个输入字段所代表的属性的名字,它是name和label属性的一个快捷方式
requiredposition String 指定一个表单元素在xhtal和Ajax主题里的标签必须出现的位置,可取值是left和right(默认值)
*name String 指定HTML name属性,一个输入元素的name属性将被映射到一个Action属性
required^ boolean 在xhtal主题里,这个属性表明是否要给当前行标加上一个*号
tabIndex String 指定HTML tabIndex属性
*value String 指定一个表单元素的值
注意:*属性只在没有使用simple主题时才可以使用
3.form标签:用来呈现HTML语言中的表单元素
1).form标签的属性
名字 数据类型 默认值 说明
accepcharset String 这个表单元素接受的字符集,如果有多个字符集,用逗号或空格隔开
action St

ring 当前action 提交这个表单所触发的action
enctype String 表单的enctype属性
method String post 表单方法
namespace String 当前命名空间 提交这个表单所触发的action所在的命名空间
onsubmit String JavaScript onsubmit属性
openTemplate String 用来打开这个表单的模板
portletMode String 在用户提交的这个表单后将显示的portletMode
target String 表单的target属性
validate Boolean FALSE 在xhtal/ajax主题下,是否进行客户端输入验证
windowState String 在用户 提交这个表单后将显示的窗口状态
2).默认情况下,form标签将被呈现为一个表格形式的HTML表单,嵌套在form标签里的输入字段将被呈现为一个表格行,每个表格行有两个字段组成,
一个对应着标,一个对应着输入元素,提交按钮将被呈现为一个横跨两列单元格的行。
4.textfield,password,hidden标签
1).textfield标签将被呈现为一个输入文本字段,password标签将被呈现为一个口令字段,hidden标签将被呈现为一个不可见字段
2).属性:
名字 数据类型 默认值 说明
maxlength integer 由这个标签呈现出来的HTML元素所能容纳的字符最大个数
readonly Boolean FALSE 用来表明该输入元素是不是只读的
size integer 尺寸属性
3).password标签扩展自textfield标签,多了一个showPassword属性,该属性是布尔型,默认值FALSE,
它决定着在表单回显时是否显示输入的密码。
eg:



5.submit标签
1).submit标签将被呈现为一个提交按钮,根据其type属性的值,这个标签可以提供3中呈现效果。
->input:
->button:
->image:
2).submit标签的属性
名字 数据类型 默认值 说明
action String HTML action属性
align String HTML align属性
method String method属性
type String input 这个属性的值决定着提交按钮的屏显效果类型,它的可取值是input,button或image
6.textarea标签
1).textarea标签将呈现一个HTML文本域元素
2).textarea标签的属性
名字 数据类型 默认值 说明
cols integer HTML cols属性
readonly boolean false 用来表明该textarea元素是不是只读的
rows integer HTML rows属性
wrap Boolean HTML wrap属性
eg:

7.checkbox标签
1).checkbox标签将呈现为一个HTML复选框元素,该复选框元素通常用于提交一个布尔值
2).当包含着一个复选框的

表单被提交时,如果某个复选框被选中了,它的值将为TRUE,这个复选框
在HTTP请求里增加一个请求参数,但如果该复选框未被选中,在请求中就不会增加一个请求参数
3).checkbox标签解决了这个局限性,他采取的办法是为单个复选框元素创建一个配对的不可见字段




8.radio标签
1).radio标签将呈现为一组单选按钮,单选那妞的个数与程序员通过该标签的List属性提供的
选项的个数相同。
2).一般地,使用radio标签实现多选一,对于真假则使用checkbox标签。
3).radio标签的属性:
名字 数据类型 默认值 说明
list String 用来充当选项来源的可遍历对象
listKey String 用来提供选项值的对象属性
listValue String 用来提供选项行标的对象属性
eg:

9.select标签
1). select标签的属性
名字 数据类型 默认值 说明
headerKey String 选项列表中的第一个选项的键
headerValue String 选项列表中的第一个选项的值
list String 用来充当选项来源的可遍历对象
listKey String 用来提供选项值的对象属性
listValue String 用来提供选项行标的对象属性
multiple Boolean false 指明是否允许多重选择(多选多)
size integer 同时显示在页面里的选项的个数
eg:
listKey="cityId" listValue="cityName" multiple="true">

10.optiongroup标签:对select元素所提供的选项进行分组,每个选项有他自己的来源
1).属性列表:
名字 数据类型 默认值 说明
list String 用来充当选项来源的可遍历对象
listKey String 用来提供选项值的对象属性
listValue String 用来提供选项行标的对象属性
eg:





11.checkboxlist标签:将呈现一组多选框
1).属性列表:

字 数据类型 默认值 说明
list String 用来充当选项来源的可遍历对象
listKey String 用来提供选项值的对象属性
listValue String 用来提供选项行标的对象属性
2).checkbox被映射到一个字符串数组或是一个基本类型的数组,若它提供的多选框一个也没有别选中,相应的属性将被赋值为一个空数组而不是空值。
eg:





十三.主题:
1.主题是为让所有的UI标签能够产生同样的视觉效果二归集到一起的一组模板,即风格相近的模板被打包为一个主题。
1).simple:把UI标签翻译成最简单的HTML对应元素,而且会忽视行标
2).xhtml:xhtml是默认主题,这个主题的模板通过使用一个布局表格提供了一个自动化的排版机制。
3).css_xhtml:这个主题里的模板与xhtml主题里的模板很相似,但它们将使用css来进行布局和排版
4).ajax:这个主题里的模板一xhtml主题里的里德模板为基础,但增加了一些aAjax功能。
2.修改主题
1).通过UI标签的theme属性
eg:
2).在一个表单里,若没有给出某个UI标签的theme属性,它将使用这个表单的主题
3).在page,request,session或application中添加一个theme属性
eg:request.setAttribute("theme", "simple");
4).修改struts.properties文件中的struts.ui.theme属性
eg:


十四.ModelDriver和Preparable拦截器
1.Params拦截器:Parameters拦截器把表单字段映射到ValueStack栈的栈顶对象的各个属性中。
如果某个字段在模型里没有匹配的属性,Param拦截器将尝试映射到ValueStack栈中的下一个对象。
2.Action实现ModelDriven接口后的运行流程:
1).先回执行ModelDrivenInterceptor的intercept方法:
public String intercept(ActionInvocation invocation) throws Exception {
//获取Action对象:EmployeeAction对象,此时该Action已经实现了ModelDriven接口
//public class EmployeeAction implements RequestAware,ModelDriven{}

Object action = invocation.getAction();
//判断Action是否是ModelDriven的实例
if (action instanceof ModelDriven) {
//强制转换为ModelDriven类型
ModelDriven modelDriven = (ModelDriven) action;
//获取值栈
ValueStack stack = invocation.getStack();
//调用ModelDriven接口的getModel()方法
//即调用EmployeeAction的getModel()方法
/*
public Employee getModel() {

employee = new Employee();
return employee;
}
*/
Objct model = modelDriven.getModel();
if (model != null) {
//把getModel()方法的返回值加入到值栈的栈顶 ,实际上压入的是EmployeeAction的employee成员变量
stack.push(model);
}
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
2).执行ParametersInterceptro的intercept方法:把请求参数的值赋给栈顶对象对应的属性,
若栈顶对象没有对应的属性,则查询值栈中下一个对象对应的属性。
3).注意:getModel()方法不能提供以下实现,这种实现的确实惠返回一个Employee对象到值栈,但当前Action的employee成员变量却是null:
public Empployee getMoel(){ return new Employee();}

3.使用paramsPrepareParamsStack拦截器栈
1).paramsPrepareParamsStack和defaultStack一样否是拦截器栈,而struts-default包默认使用的是defaultStack
2).可以再Struts配置文件中使用以下放肆修改使用的默认拦截器栈

3).paramsPrepareParamsStack 拦截器
(1).先执行params拦截器,然后prepare拦截器,在执行modelDriven拦截器,最后执行params拦截器。
所以可以先把请求参数赋给Action对应的属性,在根据赋给Action的那个属性值决定压入值栈栈顶的对象,最后为该栈顶对象的属性赋值。
(2).对于edit操作而言:
①.先为EmployeeAction的employeeId赋值
②.根据employeeId从数据库中加载对应的对象,并放入到值栈的栈顶。
③.再为栈顶对象的employeeId赋值(实际上此时employeeId属性值已经存在)。
④.再把栈顶对象的属性回显到表单中。
4).关于回显:Struts2表单标签会从值栈中获取对应的属性显示到表单中
5).运行流程:
(1).params拦截器首先给 Action中的相关的参数赋值,如id
(2).prepare拦截器执行prepare方法,prepare方法会根据参数,如id,取调用业务逻辑,设model对象
(3).modelDriven拦截器将model对象压入valueStack,这里的model对象就是在prepare创建的
(4).params拦截器再将参数赋值给model对象
(5).action的业务逻辑执行
6).存在的问题:
getModel()方法:
public Employee getModel() {
if(employeeId == null)
employee = new Employee();
else
employee = dao.get(employeeId);
return employee;
}
(1).在执行删除的时候,employeeId不为null,但getModel()方法却从数据库正加载了一个对象,但这是没不要的。
(2).在执行查询全部信息(list)时:,此时e

mployeeId为null,但也new了一个Employee对象
7).解决方案:使用PrepareInterceptor和Preparable接口
4.关于PrepareInterceptor拦截器
1).doIntercept方法
public String doIntercept(ActionInvocation invocation) throws Exception {
//获取Action实例
Object action = invocation.getAction();
//判断Action是否实现了Preparable接口
if (action instanceof Preparable) {
try {
String[] prefixes;
//根据当前拦截器的firstCallPrepareDo(默认为FALSE)属性确定prefixes
if(firstCallPrepareDo){
prefixes = new String[] {ALT_PREPARE_PREFIX,PREPARE_PREFIX};
}else {
prefixes = new String[]{PREPARE_PREFIX, ALT_PREPARE_PREFIX});
}
//若为false,则为prefixes:prepare,prepareDo
//调用前缀方法
PrefixMethodInvocationUtil.invokePrefixMethod(invocation,prefixes);
}
catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if(casue instanceof Exception) {
throw (Exception) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
throw e;
}
}
//根据当前拦截器的alwaysInvokePrepare(默认为true)属性决定是否调用Action的prepare()方法
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
2).PrefixMethodInvocationUtil.invokePrefixMethod(invocation,prefixes)方法
public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
//获取Action实例
Object action = actionInvocation.getAction();
//获取药调用的Action方法的名字
String methodName = actionInvocation.getProxy().getMethod();

if (methodName == null) {
// if null returns (possible according to the docs), use the default execute
methodName = DEFAULT_INVOCATION_METHODNAME;
}
//获取前缀方法
Method method = getPrefixedMethod(prefixes, methodName, action);
//若方法不为null,则通过反射调用前缀方法
if (method != null) {
method.invoke(action, new Object[0]);
}
}
3).PrefixMethodInvocationUtil.getPrefixedMethod(String[] prefixes, String methodName, Object action)方法:
public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
assert(prefixes != null);
//把方法的首字母变为大写
String capitalizedMethodName = capitalizeMethodName(methodName);
//遍历前缀数组
for (String prefixe : prefixes) {
//通过拼接

的方式,得到前缀方法名:第一次是prepareXxx,第二次是prepareDoXxx
String prefixedMethodName = prefixe + capitalizedMethodName;
try {
//利用反射从Action中获取对应的方法,若有直接返回,并结束循环
return action.getClass().getMethod(prefixedMethodName, new Class[0]);
}
catch (NoSuchMethodException e) {
// hmm -- OK, try next prefix
if (LOG.isDebugEnabled()) {
LOG.debug("cannot find method [" + prefixedMethodName + "] in action [" + action + "]");
}
}
}
return null;
}
4).源代码解析:
若Action实现Prepareable接口,则Struts将尝试执行prepare[ActionMethodName]方法,
若prepare[ActionMethodName]不存在,则将尝试执行prepareDo[ActionMethodName]
若都不存在,就都不执行

若PrepareInterceptor的alwaysInvokePrepare属性为false,则Struts2将不会调用实现了Prepareable接口的Action

能解决十四.3.6的问题:
可以为每一个ActionMethod准备prepare[ActionMethodName]方法,而抛弃prepare()方法
将PrepareInterceptor的alwaysInvokePrepare属性置为false,以避免struts2框架在调用prepare()方法
如何在配置文件中设置拦截器的属性的值
eg:修改PrepareInterceptor的alwaysInvokePrepare属性值为false



false






十五.类型转换:在Struts2中,把请求参数映射到action属性的工作有Parameters拦截器负责,它是默认的defaultStack拦截器中的一员,
Parameters拦截器可以自动完成字符串和基本数据类型之间的转换。
1.类型转换错误:
1).若Action类没有实现ValidationAware接口:Struts在遇到类型转换错误时任会继续调用Action方法,就好像什么都没发生一样。
2).若Action类实现ValidationAware接口:Struts在遇到类型转换错误时将不会继续调用其Action方法:Struts将检查相关action
元素的声明是否包含着一个name为input的result,如果有,Struts将把控制权交给那个result元素,若没有input结果,Struts将抛出一个异常
3).如何覆盖默认的错误消息,如果是simple主题,还会自动发显示错误消息吗?如果不会显示,怎么办?
(1).Parameters拦截器作为default拦截器的一员,ConversionError拦截器负责添加与类型转换相关的出错信息(Action类必须实现了ValidationAware接口)
和保存各请求参数的原始值。
(2).若字段标签使用的不是simple主题,则非法输入字

段将导致一条有着以下格式的出错消息:Invalid field value for field fieldName;

(3).覆盖默认的出错消息
①.在对应的Action类所在的包中新建ActionClassName.properties文件,ActionClassName即为包含着输入字段的Action类的类名
②.在属性文件中添加以下键值对:invalid.fieldvalue.fieldName = Custom error message

(4).定制出错消息的样式:
每一条出错消息都被打包在一个Html span元素里,可以通过覆盖其行标为errorMessage的那个css样式来改变出错消息的格式
(5).显示错误消息:如果是simple主题,可以通过 标签显示错误消息
2.自定义类型转换器
1).开发类型转换器的类:扩展StrutsTypeConverter类
2).配置转换器:
(1).方式一:基于字段的配置
->在字段所在的model(可能是Action,也可能是一个JavaBean)的包下,新建一个modelClassName-conversion.properties文件,
->在该文件中输入键值对:fieldName=类型转换器的全类名
->第一次使用该转换器时创建实例。
(2).方式二:基于类型的配置
->在src下新建xwork-conversion.properties
->在该文件中输入键值对:待转换的类型=类型转换器的全类名
->当前struts2应用被加载时创建实例。
(3).对于基于字段的配置,类型转换器时单例的
对于基于类型的配置,类型转换器不是单例的。

十六.消息处理与国际化
1.国际化的目标
1).如何配置国际化资源文件
(1).基于Action的资源文件:在Action类文件所在的路径建立名为ActionName_language_country.properties的文件
(2).基于包的资源文件:在包的根路径下建立文件名为package_language_country.properties的属性文件,一旦建立,处于
该包下的所有Action都可以访问该资源文件。注意:包范围资源文件的baseName就是package,不是Action所在的包名。
(3).全局资源文件:
-> 命名方式:basename_language_country.properties
-> struts.xml:
-> struts.properties : struts.custom.i18n.resources=basename
(4).临时指定资源文件:标签的name属性指定临时的国际化资源文件。
(5).国际化资源文件加载的顺序:离当前Action越近的资源文件将被优先加载。
假设我们在某个ChildAction中调用了getText("username"):
-> ①.加载和ChildAction的类文件在同一个包下的系列资源文件ChildAction.properties
-> ②.加载ChildAction实现的接口IChi看到,且和IChild在同一个包下的IChild.properties系列资源文件
-> ③.加载ChildAction父类Parent,且和Parent在同一个包下的baseName为Parent.properties系列资源文件
-> ④.若ChildAction实现了ModelDriven接口,则对于ge

tModel()方法返回的model对象,重新执行第①步操作
-> ⑤.查找当前包下package.properties系列资源文件
-> ⑥.沿着当前包上溯,直到最顶层包查找package.properties的系列资源文件
-> ⑦.查找struts.custome.i18n.resources常量指定baseName的系列资源文件
-> ⑧.直接输出该key的字符串值
2).如何在页面上和Action类中访问国际化资源文件的value值
(1).在Action类中,若Action类实现了TestProvider接口,则可以调用getText()方法获取value值。
-> 通过继承ActionSupport的方式
(2).页面上可以使用s:text标签;对于表单标签可以使用表单标签的key属性值
-> 若有占位符,则可以使用s:text标签的s:param子标签来填充占位符
-> 若当前页面来自Action,可以利用标签和OGNL表达式访问之战中的属性值(包括对象栈和Map栈)。
3).实现通过超链接切换语言
(1).关键之处在于知道Struts2框架式如何确定Locale对象的
(2).具体确定Locale对象的过程:
-> Struts2使用i18n拦截器处理国际化,并且将其注册在默认的拦截器栈中
-> i18n拦截器在执行Action方法之前,自动查找请求中一个名为request_locale的参数
如果参数存在,拦截器将就其作为参数,转换成Locale对象,并将群其设为默认的Locale(代表国家/语言环境)。
并将其设置为session的WW_TRANS_I18N_LOCALE属性。
-> 如果request中没有名为request_Locale参数,则i18n拦截器会从Session获取WW_TRANS_I18N_LOCALE的属性值。
若该值不为空,则将该属性设置为浏览器的默认Locale。
-> 若session中的WW_TRANS_I18N_LOCALE的属性为空,则从ActionContext中获取Locale对象。
(3).具体实现:只需要在超链接的后面附着request_locale的请求参数,值是语言国家代码 :
eg:
English
中文
注意:超链接必须是一个Struts2的请求,即为了使i18n拦截器工作。


十七.Struts2运行流程分析
1.
1).
1).
1).
1.
1.


十八.输入验证
1.验证分为两种:
1).声明式验证:
(1).对哪个Action或Model的哪个字段进行验证
(2).验证规则
(3).验证失败的结果
1).编程式验证

2.声明式验证:
1).明确对哪一个Action的哪一个字段进行验证
2).编写配置文件
(1).把struts-2.1.8\apps\struts2-blank-2.1.8\WEB-INF\classes\example下的Login-validation.xml文件
复制打当前Action所在的包下,
(2).把文件的名字改为ActionClassName-validation.xml
(3).添加验证规则:参见struts-2.1.8\docs\WW下的validation.html文档
eg:


You must ente

r a value for bar.


6
10
bar must be between ${min} and ${max}, current value is ${bar}.


(4).验证失败的结果:验证失败则转向input的那个result,所以需要配置name=input的result
/validation.jsp
(5).如何显示错误消息,在配置文件中定制错误消息
-> 若使用的是非simple主题,则自动显示错误消息:
bar must be between ${min} and ${max}, current value is ${bar}.
-> 若使用的是simple主题:使用s:fieldErrors或EL表达式显示错误消息
eg:
${fieldErrors.age[0]}


-> 错误消息可以国际化:把错误消息房子啊国际化资源文件 中
eg:
在验证规则文件中给message节点加入一个key属性
age must be between ${min} and ${max}, current value is ${age}.
再在国际化资源文件中加入一个键值对:键:message节点的key属性,值:错误消息
age.int=Age must be between ${min} and ${max}, current value is ${age}.
age.int=Age 必须在${min} 和 ${max}之间, 当前Age的值是 ${age}.
age.int=Age must be between ${min} and ${max}, current value is ${age}.
3).若一个Action可以应答多个action请求,多个action请求使用不同的验证规则:
(1).为每一个不同的action请求定义其对应的验证文件:ActionClassName-AliasName-validation.xml
(2).不带别名的配置文件:ActionClassName-validation.xml依然会发生作用,可以把各个action公用的验证规则配置其中,
但需要注意的是:只适用于某一个action请求的验证规则就不要配置在其中了。
4).声明式验证框架的原理:
(1).Struts2默认的拦截器栈中提供了一个validation拦截器
(2).每个具体的验证规则都会对应具体的一个验证器,有一个配置文件把验证规则名称和验证器关联起来了,而实际上验证的是那个验证器
该验证器位于com.opensymphony.xwork2.validator.validators下的default.xml文件中
5).短路验证:若对一个字段使用多个验证器,默认情况下会执行所有的验证。
若希望的前面的验证器没有通过,后面的就不在验证,可以使用短路验证。
eg:

Conversion Error Occurred

6).若类型转换失败,还会执行后面的拦截器,还会进行验证,可以通过修改ConversionErrorInterceptor源代码的方式使当类型转换失败时,不在执行后续的拦截器,而直

接返回input的result
Object action = invocation.getAction();
if(action instanceof ValidationAware){
ValidationAware va = (ValidationAware) action;
if(va.hasFieldErrors() || va.hasActionErrors()){
return "input";
}
}
7).关于非字段验证:不是针对某一个字段的验证


Password is not equels to password2

显示非字段验证的错误消息,使用s:actionError标签:
8).Struts2内建的验证程序:参见struts-2.1.8\docs\WW下的validation.html文档
-> conversion validator
-> date validator
-> double validator
-> email validator
-> expression validator
-> fieldexpression validator
-> int validator
-> regex validator
-> required validator
-> requiredstring validator
-> stringlength validator
-> url validator
-> visitor validator
9).错误消息的重用性:
不同的字段使用同样的验证规则,而且使用同样的响应消息
eg:
age=Age
count=Count
error.int=${getText(fieldName)} must be between ${min} and ${max}, current value is ${age}.
3.自定义验证器:
1).自定义验证器必须实现Validation接口,Validator和FieldValidatorSupport实现了Validator接口
(1).若需要普通的验证程序,可以继承ValidatorSupport类
(2).若需要字段验证程序,可以继承FieldValidatorSupport类
(3).若验证程序需要接受一个输入参数,需要为这个参数增加一个相应的属性。
2).注册验证程序:自定义验证器需要在类路径里的某个validators.xml文件里注册,
验证框架首先在根目录下加载validators.xml文件,在该文件中加载验证器,
该文件的定义方式同默认的验证器配置文件:com.opensymphony.xwork2.validator.validators下的default.xml文件。
若没找到validators.xml文件,验证框架将调用默认的验证设置,即default.xml里面的配置信息。
eg:自定义一个18位身份证验证器



十九.文件的上传和下载
1.表单需要注意的3点:
2.文件上传实际上使用的是commons FileIpload组件,所以需要导入
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
3.Struts2进行文件上传需要使用FileUpload拦截器
4.基本文件上传:直接在Action中定义如下3个属性,并提供对应的getter和setter方法:
//文件对应的File对象
private File [fielFieldName];
//文件类型
private String fileContentType;
//文件名
private String fileName;
5.使用IO流进行文件的上传
eg:
ServletContext servletContext = ServletActionContext.getServletContext();
//设置文件上传到的目录
String dir = servletContext.getRealPath("/files/"+fileName);
//得

相关文档