一、OGNL
1、OGNL概述
(1) OGNL的概念
对象导航图语言(Object Graph Navigation Language),简称OGNL,是应用于Java中的一个开源的表达式语言(Expression Language),它被集成在Struts2等框架中,作用是对数据进行访问,它拥有类型转换、访问对象方法、操作集合对象等功能。
–百度百科
OGNL:对象图导航语言,比EL表达式强大很多倍的语言。调用对象的方法,获取struts2的值栈的数据。OGNL其实是一个第三方的表达式语言。
EL:从域对象中获取数据,从EL的11个对象中获取。
n
a
m
e
{ name }
name{ pageContext.request.contextPath }
(2) OGNL的特点
- 支持对象方法调用,如xxx.doSomeSpecial();
- 支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format(‘foo %s’, ‘bar’)或@tutorial.MyConstant@APP_NAME;
- 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(price*discount),这个表达式会返回80;
- 访问OGNL上下文(OGNL context)和ActionContext;
- 操作集合对象。
- 可以直接new一个对象
(3) OGNL使用的要素
- 表达式
- 跟对象
- Context对象
2、OGNL的Java环境入门(了解)
(1) 访问对象的方法
@Test
/**
* OGNL调用对象的方法
*/
public void demo1() throws OgnlException {
// 获得context
OgnlContext context = new OgnlContext();
// 获得跟对象
Object root = context.getRoot();
// 执行表达式
Object object = Ognl.getValue("'helloworld'.length()", context, root);
System.out.println(object);
}
(2) 访问对象的静态方法
@Test
// 访问对象的静态方法
public void demo2() throws OgnlException {
// 获得context
OgnlContext context = new OgnlContext();
// 获得跟对象
Object root = context.getRoot();
// 执行表达式:@类名@方法名
Object obj = Ognl.getValue("@java.lang.Math@random()", context, root);
System.out.println(obj);
}
(3) 获得Root中的数据
访问Root中的数据,不需要加 # 号
@Test
// 访问Root中的数据,不需要加#
public void demo3() throws OgnlException {
// 获得context
OgnlContext context = new OgnlContext();
User user = new User("Brown", "123456");
context.setRoot(user);
// 获得跟对象
Object root = context.getRoot();
Object username = Ognl.getValue("username", context, root);
Object password = Ognl.getValue("password", context, root);
System.out.println(username + " " + password);
}
(4) 获得OgnlCOntext中的数据
访问Context中的数据,需要加 # 号
@Test
// 访问Context中的数据,需要加#
public void demo4() throws OgnlException {
// 获得context
OgnlContext context = new OgnlContext();
// 获得跟对象
Object root = context.getRoot();
// 向Context中存入数据
context.put("name", "Browen");
// 执行表达式
Object obj = Ognl.getValue("#name", context, root);
System.out.println(obj);
}
3、OGNL的Struts2环境入门
(1) 访问对象的方法
jsp文件:
<h1>OGNL在struts2环境入门</h1>
<h3>调用对象的方法</h3>
<s:property value="'struts'.length()"/>
(2) 访问对象的静态方法
jsp文件:
<h3>调用对象的静态方法</h3>
<!-- 静态方法的访问默认是关闭的,需要开启常量 -->
<s:property value="@java.lang.Math@random()"/>
在struts.xml中打开静态方法常量:
<!-- 开启静态方法访问 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
二、值栈
1、值栈的概述
(1) 什么是值栈
ValueStack是Struts的一个借口,字面意思为值栈,OgnlValueStack是ValueStack的实现类,客户端发出一个请求,struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例。OgnlValueStack贯穿整个Action的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
ValueStack其实类似于一个数据中转站(Struts2的框架当中的数据就都保存到了ValueStack中)。
- ValueStack接口,实现类OgnlValueStack对象。
- ValueStack贯穿整个Action的生命周期。(Action一旦创建,框架就会创建一个ValueStack对象)。
(2) 值栈的内部结构
- ValueStack中有两个主要区域:
- root区域:其实就是一个ArrayList,里面一般放置对象。获取root的数据不需要加#号。
- context区域:其实就是一个Map,里面放置的是web开发的常用的对象数据的引用。获取context数据需要加#号。
- request
- session
- application
- parameters
- attr:从小范围查找数据。
- 所说的操作值栈,通常指的是操作的ValueStack中的root区域。
(3) 值栈与ActionContext的关系
- ActionContext:Action的上下文。
- 通过源码查看到:当请求过来的时候, 执行过滤器中doFilter方法,在这个方法中创建ActionContext,在创建ActionContext过程中,创建ValueStack对象,将ValueStack对象传递给ActionContext对象。所以可以通过ActionContext获取值栈对象。
- ActionContext对象能够访问Servlet的API(访问的是域对象的数据),是因为其内部的值栈的引用。
- ServletContext:Servlet的上下文。
(4) 获得值栈
- 通过ActionContext对象获取值栈。
// 第一种:通过ActionContext获得:
ValueStack valueStack = ActionContext.getContext().getValueStack();
- 在Struts2的内部,将值栈存入request中一份。
// 第二种:通过request对象获得:
// struts.valueStack
ValueStack valueStack2= (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
(5) 值栈操作 - 向值栈中存入数据
- 第一种:在Action中提供属性的get方法的方式
- 默认的情况下,将Action对象压入值栈。Action的属性也会在值栈中。
Action:
public class ValueStackDemo3 extends ActionSupport {
private User user;
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
// 向ValueStack中存值
user = new User("李末", "569");
return SUCCESS;
}
}
对应的JSP:
<!-- 方式一的获取:利用Action在值栈中的特性 -->
<s:property value="user.username"/>
<s:property value="user.password"/>
- 使用ValueStack中本身的方法的方式
Action :
public class ValueStackDemo4 extends ActionSupport{
@Override
public String execute() throws Exception {
// 向值栈中保存对象
// 获得值栈对象:
ValueStack valueStack = ActionContext.getContext().getValueStack();
// 使用push(Object obj); set(String key, Object obj);
User user = new User("赵亮", "38");
// 现在user在栈顶
valueStack.push(user);
valueStack.set("name", "小刘");// 创建一个Map集合,将Map压入栈中。
return super.execute();
}
}
对应的JSP:
<!-- 方式二的获取:调用ValueStack本身的方法 -->
<s:property value="username"/>
<s:property value="password"/>
<s:property value="name"/>
(6) 获取值栈中的数据
获取值栈中的数据就是在页面中使用OGNL表达式即可。
- 获取root的数据:不需要加“#”
<!-- 获取一个对象的属性 -->
<s:property value="username"/>
<s:property value="password"/>
<!-- 获取集合当中的属性 -->
<s:property value="list[0].username"/>
<s:property value="list[0].password"/><br/>
<s:property value="list[1].username"/>
<s:property value="list[1].password"/><br/>
<s:property value="list[2].username"/>
<s:property value="list[2].password"/><br/>
- 获取context数据
<!-- 获取context中的数 -->
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<s:property value="#attr.name"/>
<s:property value="#parameters.id"/>
对应的向context中保存数据:
// 向context中存入数据:
ServletActionContext.getRequest().setAttribute("name", "r李末");
ServletActionContext.getRequest().getSession().setAttribute("name", "s赵亮");
ServletActionContext.getServletContext().setAttribute("name", "al刘铭");
(7) EL为何访问值栈数据
因为Struts2的框架的底层对request.getAttribute(String name)进行了增强。
三、OGNL中特殊字符
1、#号
(1)、获取context的数据
<h3>获取context的数据</h3>
<%
request.setAttribute("name", "李末");
%>
<s:property value="#request.name"/>
(2)、使用#号构建Map集合
<h3>构建Map集合</h3>
<s:iterator var="i" value="{ 'aa','bb','cc' }">
<s:property value="i"/> -- <s:property value="#i"/><br/>
</s:iterator>
性别:<input type="radio" name="sex3" value="1">男
<input type="radio" name="sex3" value="2">女
<hr/>
<s:radio list="#{ '1':'男', '2':'女' }" name="sex4" label="性别"></s:radio>
2、%号
(1)、强制解析OGNL
<h1>%号的用法</h1>
<%
request.setAttribute("name", "李末");
%>
姓名:<s:textfield name="name" value="%{ #request.name }"/>
(2)、强制不解析OGNL(没用)
<s:property value="%{'#request.name'}"/>
3、$号
(1)、在配置文件中使用OGNL
-
属性文件
国际化的地方使用- message_zh_CN.properties
user.login=登陆
user.welcome=欢迎,${#session.username}; - message_en_US.propertise
user.login=Login
user.welcome=Welcome,${#session.username};
- message_zh_CN.properties
-
XML文件
文件下载的时候使用- 配置:
<action name="download" class="xxx.DownloadAction">
<result type="stream">
<param name="Context-Type">文件类型</param>
<param name="Context-Disposition">attachment;filename=${文件名}</param>
</result>
</action>
四、综合案例:优化查询
1、代码实现
(1)、将查询到的数据存入到值栈中
// 查询客户列表的方法
public String find() {
// 调用业务层
CustomerService customerService = new CustomerServiceImpl();
List<Customer> list = customerService.find();
// 页面跳转
//ServletActionContext.getRequest().setAttribute("list", list);
// 将查询到的list存入到值栈中
ActionContext.getContext().getValueStack().set("list", list);
return "findSuccess";
}
(2)、在页面中用OGNL表达式获取
- 不定义var
<s:iterator value="list">
<TR
style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
<TD><s:property value="cust_name"/></TD>
<TD><s:property value="cust_level"/></TD>
<TD><s:property value="cust_source"/></TD>
<TD><s:property value="cust_industry"/></TD>
<TD><s:property value="cust_phone"/></TD>
<TD><s:property value="cust_mobile"/></TD>
<TD><a
href="${pageContext.request.contextPath }/">修改</a>
<a
href="${pageContext.request.contextPath }/">删除</a>
</TD>
</TR>
</s:iterator>
- 定义var
定义var后,把数据保存到了context区域中了。
<s:iterator var="c" value="list">
<TR
style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
<TD><s:property value="#c.cust_name"/></TD>
<TD><s:property value="#c.cust_level"/></TD>
<TD><s:property value="#c.cust_source"/></TD>
<TD><s:property value="#c.cust_industry"/></TD>
<TD><s:property value="#c.cust_phone"/></TD>
<TD><s:property value="#c.cust_mobile"/></TD>
<TD><a
href="${pageContext.request.contextPath }/">修改</a>
<a
href="${pageContext.request.contextPath }/">删除</a>
</TD>
</TR>
</s:iterator>
最近几天遇到一些事,学习效率不高,Struts2第三次笔记迟迟没有完成。。。。哎,继续努力。加油!!!