1.Struts Action
虽然,理论上Struts2的Action无须实现任何接口或继承任何类型,但是,我们为了方便实现Action,大多数情况下
都会继承com.opensymphony.xwork2.ActionSupport类,并重载(Override)此类里的String execute()方法.
1)基本原理
a.每次请求都会创建一个新的Action的实例,因为每次请求都对应一个单独的Action,所以不要考虑线程安全
b.新创建的Action对象将置于ValueStack的栈顶
c.Action的业务方法(默认为execute)根据输入算输出
2)在Action中如何访问Session&Application
方法一:
使用ActionContext访问Session.如:
ActionContext ctx=ActionContext.getContext();
Map session=ctx.getSession();
或者
Map application=ctx.getApplication();
session,application将存放在ValueStack的Context中.
在jsp页面中取值为:<s:property value="session">,
如:<s:property value="user.username">
不推荐使用ActionContext访问Session的方式,因为这种方式的“侵入性”较强
方法二:
通过实现SessionAware接口访问Session(推荐使用这种方式).
实现步骤:
首先,新建一个BaseAction,让它实现SessionAware接口
其次,所有需要session的Action继承BasseAction即可,类似的,还有:
ServletRequestAware
ServletResponseAware
ServletContextAware
如果在action中
public String login(){
session.put("user",user);
return "success";
}
在jsp页面中,在session中取数据方式为:
<s:property value="#session['user'].username " />
#session['user']表示的意思是从session这个Map集合中取出key为"user"的数据.
同样的,从其它3个范围中取数据的方式是一样的,还有其他的接口:
request 对应 ServletRequestAware
response 对应 ServletResponseAware
session 对应 SessionAware
application 对应 ServletContextAware
3)使用通配符配置Action
作用:使用通配符配置Action可以减少配置Action的次数,提高开发的效率.
如:
<action name="*_*_*" class="com.tarena.outman.{1}Action" method="{2}">
<result name="success">/WEB -INF/jsp/day03/{3}.jsp</result>
</action>
其中*代表任意的字符,{1}代表第二个*的字符,{2}代表第二个*的字符,以此类推.
在地址栏中输入:http://localhost:8080/Struts/add_product_list,则
上面的代码可以转换为:
<action name="add_product_list" class="com.tarena.outman.addAction" method="product">
<result name="success">/WEB -INF/jsp/day03/list.jsp</result>
</action>
“*_*”指名称中有“_”下划线的所有action(如 a_b.action、aaa_bbb.action)
注意:“_”下划线可以是任意字符
当我们这样写时,表示所调用的Action不确定,方法也不确定,jsp文件名也不确定
4)给Action注入参数(属性注入)
一般情况下,为该Action定义一些属性,有些是用于输入的(比如表单提交用户名,密码),有些是用于输出的(比如员工列表、当前页数)
此外,还有一些属性是Action自用的参数.
在Action中,有些属性是写死的,如果修改的化,不是很方便.像这样的参数,我们就可以写在struts.xml的配置文件中
如:
<action name="default" extends="struts-default">
<result name="success">success.jsp</result>
<param name="rowsPerPage">5</param>
</action>
在Struts2启动时,Action中的rowsPerPage就会被赋予5的值
5)在 result 的配置中使用 OGNL 表达式
<result name="success" type="dispatcher">
/WEB -INF/jsp/day03/user.jsp?userId= ${user.userId}
</result>
2. Struts Result
1)Result基本原理
在Struts2中,Result的功能非常强大,Result也是类,职责是生成视图.
视图可以是多种多样的(比如JSP,JSON,报表,freeMarker等),这些视图都可以由Result负责.
在struts.xml文件中,'struts-default"是由Struts2定义好的package,在struts2-core-2.1.8.jar
中可以找到配置文件Struts-default.xml,共定义了10个<result-type>
如:
"dispatcher",对应ServletDispaterResult类,该类负责转发.如果在struts.xml中不写type属性,默认就是"dispatcher"
这10个中,Result常用类型有:
a.dispatcher 转发
b.redirect 重定向
c.redirectAction 左右和redirect一样
d.stream
e.json
3.Struts2 核心标记库
1)UI标记
常用ui标记
a. form
b. textfield
c. password
d. submit
e. textarea
f. checkbox
g. radio
h. select
Struts2标记
功能:
Struts2支持主题(theme)
Struts2标签可以实现Action数据回显到页面form表单中
a.通用属性(所有标记都具备的属性)
注:带"*"星号的属性表示任意主题,如xhtml下才可以使用
label(*) 显示的文本
labelpostion(*) 在有主题(theme)的前提下,指定label的位置 如:labelpostion="top"
required(*) 表示这是必须的,会在label后加一个*星号 默认的值为false
tooltip(*) 指示信息
tooltipIconPath(*) 提示图片的路径
-------html原来的属性--------
cssClass(html中的class)
cssStyle(html中的style)
name
value
b. <s:form><form>
theme 主题(默认的为xhtml)可选项有xhtml和simple,如果不写,默认为xhtml
namespace 命名空间 1)先引入struts2-json-plugin-2.1.8.jar工具包
action
method
这个标签可以自动将Action的属性填写到页面form表单中(密码是不被自动填写的)
c. <s:textfield>&&<s:password>
maxLength 最多输入15个字符
size 最多显示30个字符
readonly 文本框的内容是只读的,不能改,默认为false
d. <s:textarea>
cols 指定几行
rows 指定几列
e. <s:checkbox>
使用1个
<s:checkbox name="ok"/>
查看页面源代码,生成这样的html
<input type="checkbox" name="ok" value="true"/>
<input type="hidden" name="_checkbox_ok" value="true">
使用多个
写在页面
<s:ckeckbox name="product" fieldValue="1"/>
<s:ckeckbox name="product" fieldValue="2"/>
<s:ckeckbox name="product" fieldValue="3"/>
动态获得
<s:iterator value="Products"><!-products是List集合->
<s:checkbox name="product" fieldValue="%{id}"/>
注意:
Struts2标记库中<s:checkbox>优势在于:
当你选中checkbox选项,点击提交按钮,发送的请求中会提交 ..xxx.action?ok=true
当你不选择checkbox选项时,点击提交按钮,发送的请求中会提交 ..xxx.action?ok=false
而普通的checkbox如果不勾选,是不会提交xxx.action?ok=false的
f. <s:radio>
我们原来这么写
<input type="radio" name="abc" value="1"/>One
<input type="radio" name="abc" value="2"/>Two
<input type="radio" name="abc" value="3"/>Three
后来我们这么写
<s:radio list="productOptions" label="Radio" name="abc"
listValue="label" listKey="value" />
属性含义:
name
label
list OGNL--需要迭代的集合
listValue 作用于每一个选项的提示 OGNL --
listKey 作用于每一个要提交的值 OGNL --
listValue="label" listKey="value"中的"label"和"value"分别对应
g. <select>
<select name="abc">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
Struts2 标记
<s:select list="productOptions" label= "Select" name="abc"
listValue="label" listKey="value" />
属性含义:
listValue 对应每一个 Option 的文本
listKey 对应每一个 Option 提交的值
headerValue 提示头的文字
headerKey 提示头对应的提交值
4.Struts2 拦截器
1)在package 中定义拦截器
<interceptor name="" class="">
2)在package中定义拦截器栈
<interceptor-stack name="">
<interceptor-ref name="">
</interceptor-stack>
3)package中定义默认拦截器
<default-interceptor-ref name=""/>
4)action定义拦截器
<action name="" class="">
<!--表示访问该action前先调用这个拦截器-->
<interceptor-ref name="">
<param name=""></param>
</interceptor-ref>
</action>
4.1 Struts2 控制流程
a.请求到来
b.创建ValueStack(Action放栈顶),进行初始化
c.调用拦截器Interceptor,在拦截器中是可以访问ValueStack的
d.调用Action,执行execute()方法
e.调用Result,Result负责把数据显示给用户
f.最后到页面,通过标记库取出数据
4.2自定义拦截器
步骤:
首先,创建拦截器类,实现Interceptor接口
其次,实现Interceptor里面的方法
最后,在方法intercept中,写拦截业务
ActionInvocation类封装了Action调用过程中需要的一切API
例如:
//获得ValueStack对象
ValueStack st ack=actionInvocation.getStack();
//获得和设置ValueStack中的值
stack.findValue("ognl表达式");
stack.setValue(arg0,arg1);
同样,我们这样在拦截器中调用Action
//调用Action的2种方法
//第一种
String result=actionInvocation.invoke();
//第二种
String result=actionInvocation.invokeActionOnly();
两种方法的区别:
如果使用第一种,将调用Result对象,既然有Result对象,execute()方法
已经执行了返回结果,那么在自定义拦截器中,返回值是什么都可以.
如果使用第二种,将不会调用Result对象,如此一来,自定义拦截器中intercept()
方法的返回值是必须的,就想这样,可以在拦截器中决定返回哪个页面
String result=actionInvoction.invokeActionOnly();
return "fail";
所以,如果想让拦截器决定返回值是什么(返回到哪个页面),则使用第二种方法.
5.非UI标记
<s:property value="message" escape="true" default=""/>
属性:
value: 从ognl表达式中取出数据
escape: 表示value中从message取出的数据是否转义的,默认是转义的
default: 如果ognl表达式中取不到值,就显示default的值
<s:action name="" executeResult="" var=""/>
属性:
name: 表示Action的名字
executeResult: 值为true/false,true表示在页面显示action,false表示不显示
var: 把Action放入ValueStack(Context)中,如果不写就不会放,默认不放.
在页面中使用<s:property value="#xxx">的方法取得ValueStack中的数据
<s:iterator value="" status="st">
属性:
value: 要访问的集合对象
status: 访问的状态属性,可以通过"#xxx"获取相应的值,如:
"#st.index" 计数从0开始
"#st.count" 计数从1开始
"#st.first" 是否为第一个元素
"#st.modulus(n)方法 count除以n后取余
<s:date name="" format="">
处理日期的专门格式
<s:url action="" var=""/>
用于产生一个地址
属性:
action: 产生出一个地址,可以连接到某个action
var: 自定义的变量名,将产生的地址放入ValueStack中.
<s:url action="" var="" includeParams="get/none/all">
includeParams属性
值all: 表示自动将请求本页面的参数,加于本url之后
值none: 表示没有此功能(默认)
值get: 表示仅get请求本页面的参数,加于本url之后
如果连接不是一个action,可以使用value属性
<s:url action="" var="" value="http://www.sina.com">
<s:set var="" value="" scope=""/>
从valuestack中取出数据,放入4个范围俄中(pageContext,request,session,application)
属性:
scope: 指定4个范围之一
value: ognl表达式
var: 自定义变量名,将产生的地址放入valuestack中
<s:if test="ognl判断表达式">满足条件</s:if>
<s:else>不满足条件</s:else>