Struts2的Servlet的API的访问
* 解耦合的方式:通过ActionContext对象
* 实现特定接口的方式:实现ServletRequestAware,ServletContextAware,ServletResponseAware
* 通过ServletActionContext获取
Struts2的结果页面的配置
* 结果页面的分类:
* 全局结果页面:针对一个包下的所有的action都生效
* 局部结果页面:针对一个action生效
* 结果页面的类型
* 通过type属性进行配置:
* dispatcher
* chain
* redirect
* redirectAction
* stream
Struts2的数据封装
* 属性驱动
* 提供属性的set的方法
* 提供页面OGNL表达式的方式
* 模型驱动
* 采用模型驱动实现
1.2 案例:CRM的客户查询操作
1.2.1 案例需求
CRM的管理系统中的客户管理:
l 查询客户:对查询进行优化.
l 添加客户
l 修改客户
l 删除客户
1.3 相关知识点
1.3.1 OGNL的表达式
1.3.1.1 什么是OGNL
OGNL:对象图导航语言,是一门功能强大的表达式语言(功能比EL强大很多倍)。Struts2将OGNL引入到自身,作为Struts2的表达式语言。
1.3.1.2 OGNL的作用
1.3.1.3 OGNL的要素:
l 表达式:
l 跟对象:
l Context对象:
1.3.2 OGNL的入门
1.3.2.1 在Java环境中使用
public class OgnlDemo1 {
@Test
/**
* OGNL调用对象的方法:
*/
public void demo1() throws OgnlException{
OgnlContext context = new OgnlContext();
Object value = Ognl.getValue("'helloworld'.length()", context, context.getRoot());
System.out.println(value);
}
@Test
/**
* OGNL调用对象的静态方法:
* @包名.类名@属性/方法
*/
public void demo2() throws OgnlException{
OgnlContext context = new OgnlContext();
Object value = Ognl.getValue("@java.lang.Math@random()", context, context.getRoot());
System.out.println(value);
}
@Test
/**
* 获得Root中的数据:获取root中的数据不需要加#
*/
public void demo3() throws OgnlException{
OgnlContext context = new OgnlContext();
User user = new User();
user.setUsername("aaa");
user.setPassword("123");
// 向root中存入数据
context.setRoot(user);
// 获取root中的数据:
Object username = Ognl.getValue("username", context, context.getRoot());
Object password = Ognl.getValue("password", context, context.getRoot());
System.out.println(username +" "+password);
}
@Test
/**
* 获取context中的数据:获取context中的数据需要加#
*/
public void demo4() throws OgnlException{
OgnlContext context = new OgnlContext();
context.put("name", "张三");
Object value = Ognl.getValue("#name", context, context.getRoot());
System.out.println(value);
}
}
1.3.2.2 在Struts2环境中使用
<h1>OGNL在Struts2环境中使用</h1>
<h3>访问对象的方法</h3>
<s:property value="'helloworld'.length()"/>
<h3>访问对象的静态方法</h3>
<s:property value="@java.lang.Math@random()"/>
1.3.3 Struts2的ValueStack
1.3.3.1 什么是ValueStack值栈
ValueStack是Struts2框架中的接口,实现类OgnlValueStack的类。ValueStack(值栈)实质就是一个Struts2的数据的中转站。ValueStack对象贯穿了Action的整个的生命周期。从客户端发送一个请求到Action,Struts2就会创建一个Action的实例,同时为这个Action的实例创建一个ValueStack对象。在执行Action过程中,Struts2框架将ValueStack存入到request域中一份。Struts2通过OGNL访问值栈的数据。
1.3.3.2 值栈的内部结构
1.3.3.3 ActionContext与值栈关系
l 为什么可以通过ActionContext获得值栈?
n ActionContext:Action的上下文。创建Action实例的时候,创建值栈对象,将值栈对象存入到ActionContext中。
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
Integer counter = 1;
Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
if (oldCounter != null) {
counter = oldCounter + 1;
}
ActionContext oldContext = ActionContext.getContext();
if (oldContext != null) {
// detected existing context, so we are probably in a forward
ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
} else {
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
ctx = new ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
ActionContext.setContext(ctx);
return ctx;
}
l ActionContext为什么访问Servlet的API?
上次课用ActionContext访问Servlet的API:
ActionContext act = ActionContext.getContext();
Map<String,Object> sessionMap = act.getSession();
sessionMap.put();
***** 这种访问Servlet的API的方式,只能操作域中数据的,不能获得真实的对象。
ActionContext中能够访问Servlet的API基于ValueStack来实现的。
1.3.3.4 获得ValueStack
l 通过ActionContext对象获取:
// 获取值栈的方式一:通过ActionContext获取:
ValueStack valueStack1 = ActionContext.getContext().getValueStack();
l 通过request域获取:
执行Action的过程中,将ValueStack存入到request域中,key是struts.valueStack。相当于request.setAttribute(“struts.valueStack”,valueStack);
// 获取值栈的方式二:通过request对象获取:
ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest()
.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
1.3.3.5 操作ValueStack
l 操作root区
n 通过值栈中的方法操作值栈
调用ValueStack中的方法:set、push
public class ValueStack3Action extends ActionSupport{
@Override
public String execute() throws Exception {
// 获得值栈:
ValueStack valueStack = ActionContext.getContext().getValueStack();
/**
* ValueStack中的方法:
* * void set(String key,Object value); -- 创建一个Map集合,将Map集合存入到值栈(root)中。
* * void push(Object obj); -- 将对象存入到值栈(root)中。
* * 栈的特点:先进后出.
*/
valueStack.set("name", "王强勇");// 一般list集合使用set
User user = new User();
user.setUsername("aaa");
valueStack.push(user); // 一般Object使用push
return SUCCESS;
}
}
n 通过Action中提供成员属性的方式
Action类默认是在栈中,而且默认情况下(没有手动向值栈存值,没有实现模型驱动)是在栈顶的位置。Action已经在值栈中了,现在提供了一个Action的属性,Action的属性也是会在栈中。
public class ValueStack3Action extends ActionSupport{
private Integer age;
public Integer getAge() {
return age;
}
..
}
l 操作context区(了解)
<s:debug></s:debug>
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#parameters.id"/>
<s:property value="#attr.name"/>
1.3.3.6 获取ValueStack中的数据
<h1>获取数据</h1>
<h3>获取push的数据</h3>
<s:property value="username"/>
<s:property value="password"/>
<h3>获取set的数据</h3>
<s:property value="user.username"/>
<s:property value="user.password"/>
<h3>获取list集合中的数据</h3>
<s:property value="list[0].username"/>
<s:property value="list[0].password"/>
<s:property value="list[1].username"/>
<s:property value="list[1].password"/>
<s:property value="list[2].username"/>
<s:property value="list[2].password"/>
<br/>
1.3.3.7 EL访问ValueStack
EL获取的数据来源都是四个作用域还有提供11操作web常用的对象。
11个web常用对象:
requestScope
sessionScope
pageScope
applicationScope
param
paramValues
header
headerValue
cookie
initparams
pageContext
因为Struts2底层对request对象进行包装:
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute";
private final boolean disableRequestAttributeValueStackLookup;
/**
* The constructor
* @param req The request
*/
public StrutsRequestWrapper(HttpServletRequest req) {
this(req, false);
}
/**
* The constructor
* @param req The request
* @param disableRequestAttributeValueStackLookup flag for disabling request attribute value stack lookup (JSTL accessibility)
*/
public StrutsRequestWrapper(HttpServletRequest req, boolean disableRequestAttributeValueStackLookup) {
super(req);
this.disableRequestAttributeValueStackLookup = disableRequestAttributeValueStackLookup;
}
/**
* Gets the object, looking in the value stack if not found
*
* @param key The attribute key
*/
public Object getAttribute(String key) {
if (key == null) {
throw new NullPointerException("You must specify a key value");
}
if (disableRequestAttributeValueStackLookup || key.startsWith("javax.servlet")) {
// don't bother with the standard javax.servlet attributes, we can short-circuit this
// see WW-953 and the forums post linked in that issue for more info
return super.getAttribute(key);
}
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(key);
if (ctx != null && attribute == null) {
boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));
// note: we don't let # come through or else a request for
// #attr.foo or #request.foo could cause an endless loop
if (!alreadyIn && !key.contains("#")) {
try {
// If not found, then try the ValueStack
ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
ValueStack stack = ctx.getValueStack();
if (stack != null) {
attribute = stack.findValue(key);
}
} finally {
ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
}
}
}
return attribute;
}
}
1.3.4 OGNL中特殊符号的使用:
1.3.4.1 #号
l 获取context中的数据
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#parameters.id"/>
<s:property value="#attr.name"/>
l 在OGNL中手动构建一个Map集合
<h1>#号构建一个Map集合</h1>
<h3>遍历List集合</h3>
<s:iterator var="i" value="{'aa','bb','cc'}">
<s:property value="#i"/><br/>
</s:iterator>
<h3>遍历Map集合</h3>
<s:iterator var="entry" value="#{'aa':'11','bb':'22','cc':'33'}">
<s:property value="key"/>--<s:property value="value"/><br/>
<s:property value="#entry.key"/>--<s:property value="#entry.value"/><br/>
</s:iterator>
<h3>使用Struts2UI标签构建Map集合的地方</h3>
传统方式:<br/>
性别:<input type="radio" name="sex" value="男"/>男<input type="radio" name="sex" value="女"/>女<br/>
性别:<input type="radio" name="sex" value="1"/>男<input type="radio" name="sex" value="2"/>女<br/>
Struts2UI标签的方式:<br/>
<s:radio list="{'男','女'}" name="sex" label="性别"/>
<s:radio list="#{'1':'男','2':'女' }" name="sex" label="性别"/>
1.3.4.2 %号
l 强制解析OGNL表达式:
<s:property value=”ognl”/> 一定会执行的。
<%
request.setAttribute("name", "王强勇");
%>
<input type="text" name="name" value="<s:property value="#request.name"/>"/>
<s:textfield name="name" value="%{#request.name}"/>
1.3.4.3 $号
l 在Struts2的配置文件中使用OGNL表达式
n 文件下载
<action name=”download” class=””>
<result name=”” type=”stream”>
<param name=”Content-Dispostion”>attachment;filename=${fileName}</param>
</result>
</action>
n 国际化
message_zh_CN.properties
welcome=您好:${#session.user.name}
message_en_US.properties
welcome=Hello:${#session.user.name}