Struts2系列文章推荐: |
---|
👉 Struts2框架(一):入门xml配置及action编写 |
👉 Struts2框架(二):封装方法&其他介绍&注入方式详解 |
👉 Struts2框架(四):控制器&其他OGNL标签&拦截器 |
👉 待更新 |
文章目录
1、OGNL初识
OGNL的概述
什么是OGNL
OGNL:对象图导航语言,比EL表达式强大很多倍的语言
EL:从域对象中获取数据,从EL的11个对象中获取
OGNL:调用对象的方法,获取Struts2的值栈的数据,OGNL其实是第三方的表达式语言,与Struts2无关,可独立运行
为什么要学习OGNL
OGNL使用的要素
*表达式 *根对象 *Context对象
OGNL的入门
OGNL的入门:Java环境入门(了解)
访问对象的方法
@Test
public void test1() throws OgnlException{
//获得OgnlContext
OgnlContext context = new OgnlContext();
//获得Root
Object root = context.getRoot();
//书写表达式并执行
Object value = Ognl.getValue("'helloworld'.length()", context, root);
System.out.println(value);
}
访问对象的静态方法
@Test
public void test2() throws OgnlException{
//获得OgnlContext
OgnlContext context = new OgnlContext();
//获得Root
Object root = context.getRoot();
//书写表达式并执行,使用静态方法要加@
Object value = Ognl.getValue("@java.lang.Math@random()", context, root);
System.out.println(value);
}
获得Root中的数据
@Test
public void test3() throws OgnlException{
//获得OgnlContext
OgnlContext context = new OgnlContext();
//先往Root中存储一些数据,比如对象
context.setRoot(new Customer("钻石王老五","黄老板推荐的"));
//获得Root
Object root = context.getRoot();
//书写表达式并执行
Object value = Ognl.getValue("cust_name", context, root);
System.out.println(value);
}
获得OGNLContext中的数据
@Test
public void test4() throws OgnlException{
//获得OgnlContext
OgnlContext context = new OgnlContext();
//获得Root
Object root = context.getRoot();
//先往Context中存储一些数据,比如对象
Map<String, String> map = new HashMap<String,String>();
map.put("cust_source", "黄老板推荐的");
context.setValues(map);
//书写表达式并执行,获取Context中的值要在前加#
Object value = Ognl.getValue("#cust_source", context, root);
System.out.println(value);
}
OGNL的入门:Struts2环境入门
访问对象的方法
<!-- Struts中使用OGNL -->
<h3>调用对象的方法</h3>
<s:property value="'helloworld'.length()"/>
访问对象的静态方法
<!-- 静态方法在Struts2中默认关闭,需在struts.xml中配置常量
struts.ognl.allowStaticMethodAccess = true-->
<h3>调用对象的静态方法</h3>
<s:property value="@java.lang.Math@random()"/>
2、ValueStack
ValueStack的概述
什么是值栈
Struts2将XWork对Ognl的扩展这一套机制封装起来,这个对象叫ValueStack。
ValueStack实际上就是一个容器。它由Struts框架创建,当前端页面如jsp发送一个请求时,Struts的默认拦截器会将请求中的数据进行封装,并入ValueStack的栈顶。
类似于一个数据中转站,Struts2框架中的数据都保存到了ValueStack中
ValueStack贯穿整个Action的生命周期。Action一旦创建了,框架就会创建一个ValueStack对象,这个对象在配置文件、Action、JSP都能取到
ValueStack的内部结构
ValueStack中有两个主要的区域(获取root不用加#)
root区域:其实就是一个ArrayList,里面一般放置对象
Context区域:其实就是一个Map,里面放置的是web开发中常用的对象数据的引用
request:该 Map 中包含当前 request 对象中的所有属性。
session:该 Map 中包含当前 session 对象中的所有属性。
application:该 Map 中包含当前 application 对象中的所有属性。
parameters:该 Map 中包含当前请求的请求参数。
attr:该 Map 按如下顺序检索某个属性:request,session,application。
所说的操作值栈,通常指的是操作ValueStack中的Root区域
注意:在 context 对象中包含了 root 对象,从 context 对象的结构中就可以查看到相关信息
除了上面查看值栈结构的方式之外,也可以通过页面的方式查看,首先新建一个bean,在传入一个bean对象并转发到jsp中,jsp页面代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>属性驱动方式获取值栈中的数据</title>
</head>
<body>
<s:debug></s:debug>
姓名:<s:property value="user.name"/><br/>
年龄:<s:property value="user.age"/>
</body>
</html>
此时在页面中点击debug即可查看完整信息,并且存的值也可以看到。这里的contents为栈存储
ValueStack与ActionContext的关系
ServletContext:Servlet的上下文
ActionContext:Action的上下文
通过源码查看到,当请求过来的时候,执行过滤器中的doFilter方法,在这个方法中创建ActionContext,在创建ActionContext过程中,创建了ValueStackFactory对象并创建了ValueStack对象,并把这个对象传给了ActionContext。所以可以通过ActionContext对象获取值栈对象
ActionContext对象之所以能够访问Servlet的API(访问是域对象的数据),因为在其内部有值栈的引用
ValueStack的获得
通过ActionContext对象获得值栈
在Struts2的内部,将值栈存入request中一份
//第一种:通过ActionContext获得
ActionContext.getContext().getValueStack();
//第二种:通过request对象获得
ServletActionContext.getRequest().getAttribute("struts.valueStack");//1
ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);//2
ValueStack的操作-向值栈中存入数据
第一种:在Action中提供属性的get方法的方式
默认情况下,会将Action对象压入到值栈,Action中的属性(对象)也会到栈中
//Action中
public String showinfo(){
user = new User("黄老板","123456");
return "show_info";
}
//JSP中
<s:debug/>
<h3><s:property value="user.username"/></h3>
<h3><s:property value="user.password"/></h3>
第二种:使用ValueStack中本身的方法的方式
//Action中
public String showinfo2(){
//获得值栈对象
ValueStack valueStack = ActionContext.getContext().getValueStack();
//使用Push(Object obj);、set(String key,Object obj);保存数据,后者保存在map中
user = new User("黄老板","456789");
valueStack.push(user);//压栈,在栈顶
valueStack.set("name", "黄先生");//将map压栈,谁靠后谁栈顶
return "show_info";
}
注意:这里name在debug中为null,是因为没有设置get方法,但是还是能通过OGNL表达式取出
获取ValueStack中的数据
获取值栈中的数据就是在页面中使用OGNL表达式即可
- 获取Root的数据
//Java中 public String showinfo(){ //获得值栈对象 User user = new User("黄老板","456789"); ValueStack valueStack = ActionContext.getContext().getValueStack(); valueStack.push(user);//压栈,在栈顶 return "show_info"; } public String showinfo2(){ List<User> list = new ArrayList<User>(); User user1 = new User("蓉老板","1"); User user2 = new User("嬷老板","2"); User user3 = new User("嬷老板","3"); list.add(user1);list.add(user2);list.add(user3); //获得值栈对象 ValueStack valueStack = ActionContext.getContext().getValueStack(); valueStack.set("list",list);//压栈,在栈顶 return "show_info"; } //JSP中 !-- 获取一个对象的数据 --> <h3><s:property value="username"/> <s:property value="password"/></h3> <!-- 获取集合中的数据 --> <h3><s:property value="list[0].username"/> <s:property value="list[0].password"/></h3> <h3><s:property value="list[1].username"/> <s:property value="list[1].password"/></h3> <h3><s:property value="list[2].username"/> <s:property value="list[2].password"/></h3>
- 获取Context的数据
//Java中 public String showinfo3(){ List<User> list = new ArrayList<User>(); User user1 = new User("蓉老板","1"); User user2 = new User("嬷老板","2"); User user3 = new User("嬷老板","3"); list.add(user1);list.add(user2);list.add(user3); //获得值栈对象 ServletActionContext.getRequest().setAttribute("list", list); ServletActionContext.getRequest().getSession().setAttribute("list", list); ServletActionContext.getServletContext().setAttribute("list", list); return "show_info"; } //JSP中 <!-- 获取集合中的数据 --> <h3><s:property value="#request.list[0].username"/> <s:property value="#request.list[0].password"/></h3> <h3><s:property value="#session.list[1].username"/> <s:property value="#session.list[1].password"/></h3> <h3><s:property value="#application.list[2].username"/> <s:property value="#application.list[2].password"/></h3> <h3><s:property value="#attr.list"/> <s:property value="#parameters.name"/></h3>
注意:这里的parameters为获取页面传递的参数
获取ValueStack中的数据
Struts2的框架的底层对request.getAttribute实现了增强,如果在request中可以直接获取到,那就返回,如果获取不到就在值栈中获取
3、OGNL表达式中的特殊字符
#号的用法
1、获取context数据 2、构建集合
<h3>使用#构建集合并获取</h3>
<!-- 这里遍历list集合 -->
<s:iterator var="i" value="{'aaa','bbb','ccc'}">
<!-- 下面的i和#i都一样 -->
<h4><s:property value="i"/>---<s:property value="#i"/></h4>
</s:iterator>
<!-- 这里遍历map集合 -->
<s:iterator var="i" value="#{'1':'aaa','2':'bbb','3':'ccc'}">
<!-- 第一种写法:如果上面的map中用了#,下面的i和#i都一样,key+value -->
<h4>第一种写法:<s:property value="i"/>---<s:property value="#i"/></h4>
<!-- 第二种写法:key和value分开显示,必须:(#+var.属性) -->
<h4>第二种写法:<s:property value="#i.key"/>---<s:property value="#i.value"/></h4>
<!-- 第三种写法:key和value分开显示,直接写属性 -->
<h4>第三种写法:<s:property value="key"/>---<s:property value="value"/></h4>
</s:iterator>
<h3>使用#创建单选框</h3>
<!-- 如果key与value一样用list集合 -->
<s:radio list="{'aa','bb','cc'}" name="sex1" label="性别"/><br/>
<!-- 如果key与value不一样用map集合 -->
<s:radio list="#{'1':'aaa','2':'bbb','3':'ccc'}" name="sex2" label="性别"/>
注意:
1、只要有关是map的,都必须在前面加#
2、radio的中,map和list都用list=""
3、当单选框内容与value一致就用list,不一致用map
4、一旦定义了var,那就在前面加#(统一规范)
%号的用法
强制解析OGNL
强制不解析OGNL(基本不用)
<s:debug/>
<h3>%号的用法</h3>
<%
request.setAttribute("name","小李");
%>
姓名:<s:textfield name="name" value="%{#request.name}" />
<!-- 强制不解析 -->
<s:property value="%{'#request.name'}" />
注意: 强制解析就是%{OGNL表达式},不解析就是%{‘OGNL表达式’}
$号的用法
在配置文件中使用OGNL
属性文件
国际化地方:
message_zh_CN.properties
user.login=登陆
user.welcome=欢迎,${#session.user.username}
message_en_US.properties
user.login=Login
user.welcome=Welcome,${#session.user.username}
xml文件
文件下载:
配置
<action name="download" class=xxx.DownloadAction>
<result type="stream">
<param name="Content-Type">文件类型</param>
<param name="Content-Disposition">attachment;filename=${文件名}</param>
</result>
</action>
4、综合案例CRM的查询优化
将查询到的数据存到值栈中
ActionContext.getContext().getValueStack().set("list", service.find());
页面中用OGNL表达式取值
<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 }/customerServlet?method=edit&custId=<s:property value="cust_id"/>">修改</a>
<a href="${pageContext.request.contextPath }/customerServlet?method=delete&custId=<s:property value="cust_id"/>">删除</a>
</TD>
</TR>
</s:iterator>