框架之struts2(二)
一.Struts2的模型驱动
1.编写要求:
\*动作类必须实现ModelDriven接口,并提供抽象方法实现
\*必须我们自己实例化模型对象
动作类:
public class CustomerAction extends ActionSupport
implements ModelDriven<CstCustomer>{
private ICustomerService customerService =new CustomerServiceImpl();
private CstCustomer customer =new CstCustomer();
public CstCustomer getModel(){
return customer;
}
/**
* 添加客户
*/
public String addCustomer(){
//保存操作
customerService.saveCustomer(customer);
return"addCustomer";
}
/**
* 添加客户页面的展示
*/
public String addCustomerUI(){
//1.获取客户来源的列表
List<CstBaseDict> basedicts = customerService.findAllCustomerSource();
//2.把查询出来的结果存入请求域中
HttpServletRequest request =ServletActionContext.getRequest();
request.setAttribute("baseDicts",basedicts);
return"addCustomerUI";
}
}
二.OGNL表达式和OGNL上下文(ContextMap)
1.OGNL:Object-Graph Navigation Language(对象图导航语言),它是一种功能强大的表达式语言,
它比EL功能强大的多:
EL只能从域对象中获取值,EL表达式只能获取数据
OGNL: \*支持对象的普通方法的调用,使用对象.方法名
\*支持访问静态属性,使用@包名.类名@属性名称
\*支持静态方法的调用,使用@包名.类名@方法名称
注意:静态方法调用需要在配置文件中单独开启,未开启时不能使用(struts.ognl.allowStaticMethodAccess)
\*支持赋值操作
\*支持访问OGNL上下文对象(OGNLContext)
\*支持操作集合对象(list和map)
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>OGNL的入门</title>
</head>
<body>
<%--1.要想使用OGNL,必须在struts2的标签中配置
2.OGNL支持普通的方法调用
<s:property value=""/>它就相当于把标签中value属性的取值输出到浏览器上
value属性的取值是一个OGNL表达式,注意不是一个字符串
如果要想让OGNL表达式就当成普通的字符串来处理的话,需要在外面套上单引号
--%>
<s:property value="OGNL-Expression"/><br/>
<s:property value="'OGNL-Expression'"/><br/><%--由于套上了单引号,所以value的取值就变成了一个普通的字符串--%>
<hr/>
<%--3.OGNL访问静态属性
使用的是@包名.类名@静态属性名称
--%>
<s:property value="@java.lang.Integer@MAX_VALUE"/>
<hr/>
<%--4.普通方法调用--%>
<s:property value="'OGNL-Expression'.length()"/>
<s:property value="'OGNL-Expression'.substring(0,5)"/>
<hr/>
<%--5.静态方法调用:
注意要想访问静态方法,必须开启配置:struts.ognl.allowStaticMethodAccess
--%>
<s:property value="@java.lang.Math@random()"/>
<hr/>
<%--6.使用OGNL操作List
注意:使用struts2的表单标签,必须提供name属性
s:radio标签是创建了一组单选按钮
list属性的取值是一个OGNL表达式,把大括号内的每个元素都当成list中的元素。
--%>
<s:radio list="{'男','女'}" name="gender" label="性别"></s:radio>
<hr/>
<%--7.使用OGNL操作Map
#{ key:value,key:value}就相当于创建了一个map集合
无论使用struts2的表单哪个标签,最终在浏览器上能解析的都是html标签。
html标签的value取值是map的key,显示浏览器上的信息是map的value。
--%>
<s:radio list="#{'male':'男','female':'女'}" name="gender" label="性别"></s:radio>
</body>
</html>
2.OGNL上下文(ContextMap)
\*关于动作类的生命周期:
动作类是多例的,每次动作访问,动作类都会实例化,所以线程是安全的,
\*关于请求动作的数据存放
在每次动作执行前,核心控制器StrutsPreparedAndExecuteFilter都会创建一个ActionContext和ValueStack对象,并且动作类是多例的,每次访问都会被创建,
这两个对象储存了整个动作访问期间用到的数据,并且把动作绑定到了线程局部变量(ThreadLocal)上,所以线程是安全的.
3.ContextMap的组成
ContextMap中存放的主要内容 | ||
Key | Value | 说明 |
ValueStack (root) | java.util.List | 它是一个list。key不是ValueStack,而是: com.opensymphony.xwork2.util.ValueStack.ValueStack 。但是我们不用! |
application | java.util.Map<String,Object> | ServletContext中的所有属性。 |
session | java.util.Map<String,Object> | HttpSession中的所有属性。 |
request | java.util.Map<String,Object> | ServletRequest中的所有属性。 |
parameters | java.util.Map | 参数 |
attr | java.util.Map | 把页面、请求、会话、应用范围内的所有属性放到一起。按照从小到大的范围搜索。 |
4.在jsp中查看OGNL上下文中的数据:
<s:debug></debug>
5.ContextMap与ActionContext和ValueStack之间的关系
\*ContextMap:它是OGNL上下文对象,是一个MAP结构,里面包含了web阶段的三个域对象中的数据(请求域,会话域和应用域),以及一个ValueStack(值栈)中的数据
\*ValueStack:它是一个list结构,里面存入的都是对象,实现了栈的特点,先进后出,它是OGNL上下文的一部分
\*ActionContext:它是一个工具类,是struts2为了方便我们快速获取和操作三个域以及值栈所提供的一个类
6.获取map中的数据:
\*获取ContextMap中的数据,使用<s:property value=""/>
\*获取ActionContext中的数据,使用\#key的方式
7.ValueStack中的存取操作
\*获取ValueStack和压栈操作:
ActionContext context = ActionContext.getContext();
ValueStack vs = context.getValueStack()
vs.push(Object);
\*获取ValueStack中的值:
借助<s:property value=""/>,使用OGNL表达式,只能根据property name来获取ValueStack中的property value,不能使用\#号
获取ValueStack中指定位置元素的属性: \[x\].propertyName,x是从0开始
8.原来EL表达式从四大域对象中依次查找属性,搜索的范围是由小到大
pageScope --> requestScope --> sessionScope --> applicationScope
9.OGNL表达式查找属性顺序:
pageScope --> requestScope --> ValueStack --> contextMap --> sessionScope --> applicationScope
三.模型驱动再分析
由于我们的动作类实现了ModelDriven接口,并且在执行动作类之前会有一个默认的拦截器栈DefaultStack为我们工作,里面有一个拦截器名称是:ModelDriven。
它判断了当前的动作类是否是ModelDriven类型,如果是的话,转成该类型,并且调用了getMode()方法,这时其实调用的是我们动作类重写接口的方法。
拦截器判断了得到的模型是否为null,如果不为null,进行压栈。(而并没有判断为null的情况,这也就是我们为什么要自己实例化模型的原因)。
接下来,就是JSP页面上form表单了,它的input元素中name属性取值全都变成了OGNL表达式,那么就会从栈顶逐个元素往下查找属性名称,并通过params拦截器给属性赋值。由于我们的模型被拦截器压栈了,所以模型跑栈顶去了,这也就是params拦截器能给我们封装成功的原因。
四.struts2的拦截器
1.拦截器:interceptor,它是struts2的一个重要组成部分,是针对我们访问action进行拦截
2.Filter与Interceptor之间的区别:
\*过滤器拦截的是请求级别
\*拦截器拦截的是对action的访问,拦截器不能拦截jsp,拦截是对action的访问,拦截到action内部所指向的方法
\*Filter是javaweb三大组件之一(另外两个:servlet和listener)
\*Interceptor是struts2框架的
3.拦截器的重要性:struts2中的很多功能是由拦截器完成的,它是对我们动作方法的增强,是AOP编程思想的一种应用方式
4.默认的拦截器栈:是一个叫defaultStack的拦截器栈,它是struts-default.xml中定义的
5.自定义拦截器:
\*编写步骤:
\*编写一个普通的类,继承自AbstractInterceptor,实现里面的抽象方法.
\*配置拦截器,声明拦截器,然后使用拦截器
声明:<interceptors><interceptor name="" class=""/> 使用:<interceptor-ref name="">
注意:当我们声明了拦截器,那么默认的拦截器就失效了
\*拦截器放行:invocation.invoke(),方法的返回值其实就是动作类中动作方法的返回值
\*多个拦截器的执行顺序:与声明顺序无关,与使用顺序有关
6.其他标签
\*<interceptor-stack name=""><interceptor-ref name=""></interceptor-stack>:定义拦截器栈
\*<default-intercepor-ref name=""> :定义默认的拦截器栈
\*<global-results> : 定义全局的结果变量
五.OGNL中特殊符号的使用
**\#**
a、取ActionContext中key时使用
例如<s:property value="\#name" />
b、OGNL中创建Map对象时使用,例如:<s:radio list="\#\{'male':'男','female':'女'\}" />
**$**
a、在JSP中使用EL表达式时使用,例如$\{name\}
b、在xml配置文件中,编写OGNL表达式时使用。
%
在struts2中,有些标签的value属性取值就是一个OGNL表达式
例如<s:property value="OGNL Expression" />
还有一部分标签,value属性的取值就是普通字符串
例如<s:textfield value="username"/>
如果想把一个普通的字符串强制看成时OGNL,就需要使用%\{\}把字符串套起来。
例如<s:textfield value="%\{username\}"/>。
当然在<s:property value="%\{OGNL Expression\}" />也可以使用,但不会这么用。
还没有评论,来说两句吧...