ognl:
概述
是一种功能强大的表达式语言
struts2把它作为了默认的表达式语言(导入jar包)
作用:
(理解)可以调用对象的方法
可以访问类的静态属性
可以访问类的静态方法
★获取值栈中的数据
例如
调用对象的方法:
<s:property value="'hello'.length()"/><br>
访问类的静态属性:
<!-- @全限定名@属性名称 -->
<s:property value="@java.lang.Math@PI"/><br>
访问类的静态方法:
<!-- @全限定名@方法名称() 前提:允许ognl访问类的静态方法-->
<s:property value="@java.lang.Math@random()"/>
获取值栈的数据
这个在后面讲
值栈:
ValueStack:接口 我们使用的是他的实现类:OgnlValueStack
ValueStack实际上就是一个容器。它由Struts框架创建,当前端页面如jsp发送一个请求时,
Struts的默认拦截器会将请求中的数据进行封装,并入ValueStack的栈顶
我把他称之为struts的临时数据中转站.当请求来的时候,struts框架会为每一次请求创建一个valuestack,
把请求中的数据(请求参数,域中的数据)获取,放入值栈.我们若向获取请求的参数可以找request拿,也可以找ValueStack拿;
我们若向往域中放入数据,可以先找到相应的域对象,然后操作;也可以通过值栈操作域中的数据.
当响应生成的时候,值栈就销毁了.
值栈的组成部分:
主要有两个东西:
root:本身是一个list
context:本身是一个map key:string value:Object
主要存放的是:
key | value |
---|---|
request | request域中的数据(map) |
session | session域中的数据(map) |
application | application域中的数据(map) |
attr | 四个域中的数据(map) |
parameters | 请求的参数(map) |
ActionContext和ValueStack的关系
我们可以把ActionContext看成是一个工具类
请求来的时候,struts会在核心过滤器中为每一次请求创建一个ActionContext,也会创建一个ValueStack
下面是核心过滤器的doFilter的代码
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);//设置编码格式,防止乱码
prepare.createActionContext(request, response);//创建ActionContext把request都传入当参数
prepare.assignDispatcherToThread();
if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);//放行不拦截的资源
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}
我们可以继续看一下createActionContext()方法
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();
//dispatcher.createContextMap()方法是把所有的数据都放入,把request的参数,已经request获取域中数据都放入context中,request对象,response对象
//然后在把这个Context放入stack对象中
stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
把这个这个stack对象通过context的构造器,传入,再创建对象
ctx = new ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
//下面这句话是绑定当前线程(ThreadLocal中)
ActionContext.setContext(ctx);
return ctx;
}
将请求的参数和域中的数据放入ValueStack中.然后将ValueStack放入ActionContext中.
ActionContext会绑定到当前线程.方便我们在自己的action中获取到所有的数据.
这个是我做个了简单的流程图
获取值栈:
获取值栈:ActionContext.getContext().getValueStack();
往值栈中存数据:
方式一:通过 push对象 set集合
★往root中放数据:
方式1:值栈的api
push(Object obj)
set(String key,Object value):底层创建了一个hashmap,将key/value作为map的键值对,然后将map放入root中
//获取值栈
ValueStack vs = ActionContext.getContext().getValueStack();
//操作
User user = new User();
user.setAge(18);
user.setUsername("三三");
vs.push(user);
//在user上面 底层是一个map集合,然后把map放入root中
vs.set("name", "思思");
方式2:通过Action的成员属性
(理解)往context中放数据:
我们看源码的时候,看到struts将值栈的context放入到了ActionContext中,我们只需要操作ActionContext就可以值栈的Context了
put(key,value) 相当于往request域中放入数据
getSession().put(key,value) 放入Session中
getApplication.put(key,value) 放入Application
例如:
private String hobby;
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public String execute() throws Exception {
hobby="抽烟喝酒烫头";
return super.execute();
}
在jsp获取值栈
★el也可以获取值栈中所有的数据
之前使用el 例如:${username}
依次从pageContext,request,session,application中查找数据,找到之后立即返回,找不到返回””
底层调用的是: pageContext.findAttribute(“username”)
先去找pageContext域中的数据
若找到立即返回
若找不到继续往下一个域中找
不在struts中ei标签的查找顺序:
找request域中
若找到立即返回
若找不到继续往下一个域中找
找session域中
若找到立即返回
若找不到继续往下一个域中找
找application域中
若找到立即返回
若找不到返回null
在struts中el 查找顺序:
pageContext – request – root – context(大map) – session – application
在核心过滤器中增强了request.getAttribute(..) 找的范围:request – root – context(大map)
底层调用了值栈的findValue方法:先查root,root中没有的话继续找context(大map)
总结:
从值栈中取数据:
获取root中的数据,ognl表达式直接写属性名称即可
<s:property value="ognl表达式"/>
扩展:先找root中的数据,找不到继续查找context(大map)中的数据,找不到返回””
获取context中数据,ognl表达式需要加”#”
<s:property value="#ognl表达式"/>