- 浏览: 319058 次
- 性别:
- 来自: 济南
文章分类
- 全部博客 (221)
- J2SE心得 (4)
- 经典帖子 (8)
- 亲身经历 (9)
- SSH框架 (12)
- 数据库 (10)
- java基础知识 (41)
- java解惑 (17)
- 软件测试 (0)
- JSP (6)
- JavaScript (8)
- jQuery学习 (12)
- 硬件知识 (1)
- 工具类 (14)
- 面试专题 (4)
- Struts2专题(学习) (14)
- Spring源码分析专题(学习) (15)
- JavaScript专题(学习) (8)
- ExtJs专题(学习) (6)
- Java Web快速入门——全十讲 (10)
- web前台 (1)
- J2ME手机方面 (1)
- 积累整理 (1)
- MyEclipse工具篇 (10)
- oracle (1)
- Android基础 (1)
最新评论
-
youjianbo_han_87:
上传成功后,无法跳转到success页面,会报2038和404 ...
Struts2使用FlashFileUpload.swf实现批量文件上传 -
showzh:
...
MyEclipse 怎么安装SVN插件 -
wpf523:
赞一个啊,楼主加油
一些比较复杂的运算符(二) -
独步天下:
request.getSession().getAttribute() 和request.getSession().setAttribute() -
HelloJava1234:
thank you
怎么改变MyEclipse默认的jsp打开方式
OGNL是XWork引入的一个非常有效的数据处理的工具。我们已经了解了OGNL的基本操作和OGNL的内部结构,接下来,我们来看看XWork对OGNL做了什么样的加强,以及OGNL的体系在Struts2中如何运转。
从例子开始
我们先从一个例子开始,看看数据在Struts2中是如何运转的。
- /**
- * @author Downpour
- */
- public class User {
- private Integer id;
- private String name;
- private Department department = new Department();
- // setter and getters
- }
- //=========================================================================
- /**
- * @author Downpour
- */
- public class Department {
- private Integer id;
- private String name;
- // setter and getters
- }
- //=========================================================================
- <form method="post" action="/struts-example/ognl.action">
- user name: <input type="text" name="user.name" value="downpour" />
- department name: <input type="text" name="department.name" value="dev" />
- <input type="submit" value="submit" />
- </form>
- //=========================================================================
- /**
- * @author Downpour
- */
- public class OgnlAction extends ActionSupport {
- private static final Log logger = LogFactory.getLog(OgnlAction.class);
- private User user;
- private Department department;
- /* (non-Javadoc)
- * @see com.opensymphony.xwork2.ActionSupport#execute()
- */
- @Override
- public String execute() throws Exception {
- logger.info("user name:" + user.getName()); // -> downpour
- logger.info("department name:" + department.getName()); // -> dev
- return super.execute();
- }
- // setter and getters
- }
- //=========================================================================
- user name: <s:property value="user.name" />
- department name: <s:property value="department.name" />
- //=========================================================================
/** * @author Downpour */ public class User { private Integer id; private String name; private Department department = new Department(); // setter and getters } //========================================================================= /** * @author Downpour */ public class Department { private Integer id; private String name; // setter and getters } //========================================================================= <form method="post" action="/struts-example/ognl.action"> user name: <input type="text" name="user.name" value="downpour" /> department name: <input type="text" name="department.name" value="dev" /> <input type="submit" value="submit" /> </form> //========================================================================= /** * @author Downpour */ public class OgnlAction extends ActionSupport { private static final Log logger = LogFactory.getLog(OgnlAction.class); private User user; private Department department; /* (non-Javadoc) * @see com.opensymphony.xwork2.ActionSupport#execute() */ @Override public String execute() throws Exception { logger.info("user name:" + user.getName()); // -> downpour logger.info("department name:" + department.getName()); // -> dev return super.execute(); } // setter and getters } //========================================================================= user name: <s:property value="user.name" /> department name: <s:property value="department.name" /> //=========================================================================
我们可以看到在JSP中,form中的元素input等,都使用OGNL的表达式作为name的值。而在form提交时,这些值都会被设置到Action中的Java对象中。而当Action转向到JSP时,Struts2的Tag又可以从Action的Java对象中,通过OGNL进行取值。
在这里,你看不到任何的OGNL的代码级别操作,因为这些都在Struts2内部进行了封装。而这些封装,都是建立在OGNL的基本概念,也就是根对象和上下文环境之上。下面就分别就这两个方面分别进行讲解。
ValueStack —— 对OGNL的加强
细心的读者可能会发现,在上面的例子中,我们使用了不同的表达式,针对Action中的不同的Java对象进行设值。再结合上一讲我们所例举的OGNL的代码操作示例,我们有强烈的理由怀疑,Struts2在内部有可能执行了这样的操作,才使得页面到Action的设值工作顺利完成:
- // "user.name" as OGNL expression, action as OGNL Root object
- Ognl.setValue("user.name", action, "downpour");
- Ognl.setValue("department.name", action, "dev");
// "user.name" as OGNL expression, action as OGNL Root object Ognl.setValue("user.name", action, "downpour"); Ognl.setValue("department.name", action, "dev");
如果这个怀疑是正确的,那么我们就能得出这样一个结论:Struts2的Action是OGNL操作的根对象。
这个结论是我们从现象上推出来的,至于它到底正确与否,我们之后可以通过源码分析来进行验证,在这里先卖一个关子,姑且认为它是正确的。不过这个结论对我们来说非常重要,因为这个结论Struts2的Tag,JSTL和Freemarker等表示层元素获取Action中变量的值打下了坚实的基础。
在Struts2(XWork)中,不仅把Action作为OGNL操作的根对象,作为对OGNL的扩展,它还引入了一个ValueStack的概念。这个概念代表了什么呢?还是让我们看看Struts2的Reference怎么说:
很明显,ValueStack依照它的结构和作用,至少为我们提供两大特性:
1. ValueStack是一个堆栈结构,堆栈中的每个元素对于OGNL操作来说,都被看作是根对象。
2. 由于ValueStack是一个堆栈结构,所以其中的元素都是有序的,对于某个OGNL表达式来说,OGNL将自堆栈顶部开始查找,并返回第一个符合条件的对象元素。
这里我们有必要对第二点啰嗦几句,举个具体的例子来说(这个例子同样摘自Struts2的Reference):如果在ValueStack中有2个对象,分别是“动物”和“人”,这两个对象都具备一个属性,叫做name,而“动物”还有一个属性叫species,“人”还有个属性叫salary。其中,“动物”对象在ValueStack的栈顶,而“人”这个对象在栈底。那么看看下面的OGNL表达式将返回什么?
- species // call to animal.getSpecies()
- salary // call to person.getSalary()
- name // call to animal.getName() because animal is on the top
species // call to animal.getSpecies() salary // call to person.getSalary() name // call to animal.getName() because animal is on the top
对于name这个属性,返回的将是“动物”的name,因为“动物”在栈顶,会被先匹配到OGNL的表达式。但是有的时候,你可能需要访问“人”的name属性,怎么办呢?你可以通过下面的方法:
[0].name // call to animal.getName() [1].name // call to person.getName()
Struts2中的OGNL上下文环境
有了ValueStack,我们再来仔细研究一下Struts2中OGNL的上下文环境。
也就是说,ActionContext是Struts2中OGNL的上下文环境。它维护着一个Map的结构,下面是这个结构的图示:
其中,ValueStack是这个上下文环境中的根对象,而除了这个根对象以外,Struts2还在这个上下文环境中放了许多额外的变量,而这些变量多数都是被XWork封装过的Servlet对象,例如request,session,servletContext(application)等,这些对象都被封装成Map对象,随着ActionContext作用于整个Action执行的生命周期中。
在这里,或许有些读者会提出问题来,为什么好好的Servlet对象要在这里被封装成Map对象呢?我想原因可能有以下两个:
1. 对Struts2的Action彻底屏蔽Servlet容器,从而无需再使用底层Servlet API进行编程。你所面对的,将永远是一个又一个的Java对象。
2. 便于各种View技术,例如JSP,Freemarker,Velocity等对ValueStack中上下文环境,尤其是Servlet对象中的数据进行读取。试想,如果在这里不将HttpServletRequest,HttpSession等Servlet对象转化成Map,那么我们将很难通过OGNL表达式,对这些Servlet对象中的值进行读取。
Struts2中使用OGNL进行计算
取值计算
有了上面的这些知识,我们就能非常容易的理解在Struts2中如何使用OGNL进行取值计算。
提问:在Struts2中,如何使用自身的Tag读取Action中的变量?
Struts2自身的Tag会根据value中的OGNL表达式,在ValueStack中寻找相应的对象。因为action在ValueStack的顶部,所以默认情况下,Struts2的Tag中的OGNL表达式将查找action中的变量。请注意,value中的内容直接是OGNL表达式,无需任何el的标签包装。
例如:<s:property value="user.name" />
提问:在Struts2中,如何使用自身的Tag读取HttpServletRequest,HttpSession中的变量?
在上面的知识中,我们知道,Struts2中OGNL的上下文环境中,包含request,session,application等servlet对象的Map封装。既然这些对象都在OGNL的上下文中,那么根据OGNL的基本知识,我们可以通过在表达式前面加上#符号来对这些变量的值进行访问。
例如:<s:property value="%{#application.myApplicationAttribute}" />
<s:property value="%{#session.mySessionAttribute}" />
<s:property value="%{#request.myRequestAttribute}" />
<s:property value="%{#parameters.myParameter}" />
在这里啰嗦一句,在Tag的value中包括%{开头和}结尾的字符串,不知道Struts2为什么要做出这样的设置,从源码上看,它似乎没有什么特别额外的作用:
- if (value == null) {
- value = "top";
- }
- else if (altSyntax()) {
- // the same logic as with findValue(String)
- // if value start with %{ and end with }, just cut it off!
- if (value.startsWith("%{") && value.endsWith("}")) {
- value = value.substring(2, value.length() - 1);
- }
- }
- // exception: don't call findString(), since we don't want the
- // expression parsed in this one case. it really
- // doesn't make sense, in fact.
- actualValue = (String) getStack().findValue(value, String.class);
- ......
if (value == null) { value = "top"; } else if (altSyntax()) { // the same logic as with findValue(String) // if value start with %{ and end with }, just cut it off! if (value.startsWith("%{") && value.endsWith("}")) { value = value.substring(2, value.length() - 1); } } // exception: don't call findString(), since we don't want the // expression parsed in this one case. it really // doesn't make sense, in fact. actualValue = (String) getStack().findValue(value, String.class); ......
有兴趣的朋友可以研究一下,这一对符号的原理究竟是什么。
提问:在Struts2中,如何使用JSTL来读取Action中的变量?
这是一个历史悠久的问题。因为事实上,很多朋友(包括我在内)是不使用Struts2自身的标签库,而是使用JSTL的,可能因为JSTL标签库比较少,简单易用的原因吧。
我们知道,JSTL默认是从page,request,session,application这四个Scope逐次查找相应的EL表达式所对应的对象的值。那么如果要使用JSTL来读取Action中的变量,就需要把Action中的变量,放到request域中才行。所以,早在Webwork2.1.X的年代,我们会编写一个拦截器来做这个事情的。大致的原理是:在Action执行完返回之前,依次读取Action中的所有的变量,并依次调用request.setAttribute()来进行设置。具体的整合方式,请参考以下这篇文档:http://wiki.opensymphony.com/display/WW/Using+WebWork+and+XWork+with+JSP+2.0+and+JSTL+1.1
不过随着时代的发展,上面的这种方式,已经不再被推荐使用了。(虽然如此,我们依然可以学习它的一个解决问题的思路)目前来说,自从Webwork2.2以后,包括Struts2,都使用另外一种整合方式:对HttpServletRequest进行装饰。让我们来看一下源码:
- public class StrutsRequestWrapper extends HttpServletRequestWrapper {
- /**
- * The constructor
- * @param req The request
- */
- public StrutsRequestWrapper(HttpServletRequest req) {
- super(req);
- }
- /**
- * Gets the object, looking in the value stack if not found
- *
- * @param s The attribute key
- */
- public Object getAttribute(String s) {
- if (s != null && s.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(s);
- }
- ActionContext ctx = ActionContext.getContext();
- Object attribute = super.getAttribute(s);
- boolean alreadyIn = false;
- Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute");
- if (b != null) {
- alreadyIn = b.booleanValue();
- }
- // note: we don't let # come through or else a request for
- // #attr.foo or #request.foo could cause an endless loop
- if (!alreadyIn && attribute == null && s.indexOf("#") == -1) {
- try {
- // If not found, then try the ValueStack
- ctx.put("__requestWrapper.getAttribute", Boolean.TRUE);
- ValueStack stack = ctx.getValueStack();
- if (stack != null) {
- attribute = stack.findValue(s);
- }
- } finally {
- ctx.put("__requestWrapper.getAttribute", Boolean.FALSE);
- }
- }
- return attribute;
- }
- }
public class StrutsRequestWrapper extends HttpServletRequestWrapper { /** * The constructor * @param req The request */ public StrutsRequestWrapper(HttpServletRequest req) { super(req); } /** * Gets the object, looking in the value stack if not found * * @param s The attribute key */ public Object getAttribute(String s) { if (s != null && s.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(s); } ActionContext ctx = ActionContext.getContext(); Object attribute = super.getAttribute(s); boolean alreadyIn = false; Boolean b = (Boolean) ctx.get("__requestWrapper.getAttribute"); if (b != null) { alreadyIn = b.booleanValue(); } // note: we don't let # come through or else a request for // #attr.foo or #request.foo could cause an endless loop if (!alreadyIn && attribute == null && s.indexOf("#") == -1) { try { // If not found, then try the ValueStack ctx.put("__requestWrapper.getAttribute", Boolean.TRUE); ValueStack stack = ctx.getValueStack(); if (stack != null) { attribute = stack.findValue(s); } } finally { ctx.put("__requestWrapper.getAttribute", Boolean.FALSE); } } return attribute; } }
看到了嘛?这个类会在Struts2初始化的时候,替换HttpServletRequest,运行于整个Struts2的运行过程中,当我们试图调用request.getAttribute()的时候,就会执行上面的这个方法。(这是一个典型的装饰器模式)在执行上面的方法时,会首先调用HttpServletRequest中原本的request.getAttribute(),如果没有找到,它会继续到ValueStack中去查找,而action在ValueStack中,所以action中的变量通过OGNL表达式,就能找到对应的值了。
在这里,在el表达式广泛使用的今天,JSTL1.1以后,也支持直接使用el表达式。注意与直接使用struts2的tag的区别,这里需要使用el的表示符号:${}
例如:${user.name}, <c:out value="${department.name}" />
提问:在Struts2中,如何使用Freemarker等模板来读取Action中的变量以及HttpServletRequest和HttpSession中的变量?
Freemarker等模板在Struts2中有对应的Result,而在这些Result中,Freemarker等模板会根据ValueStack和ActionContext中的内容,构造这些模板可识别的Model,从而使得模板可以以他们各自的语法对ValueStack和ActionContext中的内容进行读取。
有关Freemarker对于变量的读取,可以参考Struts2的官方文档,非常详细:http://struts.apache.org/2.0.14/docs/freemarker.html
设值计算
Struts2中使用OGNL进行设值计算,就是指View层传递数据到Control层,并且能够设置到相应的Java对象中。这个过程从逻辑上说需要分成两步来完成:
1. 对于每个请求,都建立一个与相应Action对应的ActionContext作为OGNL的上下文环境和ValueStack,并且把Action压入ValueStack
2. 在请求进入Action代码前,通过某种通用的机制,搜集页面上传递过来的参数,并调用OGNL相关的代码,对Action进行设值。
上面的第一个步骤,在处理URL请求时完成,而第二个步骤,则涉及到另外一个XWork的核心知识:拦截器。所以有关Struts2使用OGNL进行设值计算的详细分析,将会在拦截器章节具体给出。
发表评论
-
Struts2几个常用标签的主要属性及示例(一)
2010-03-29 14:17 1039以前做过一个struts2的项目,总结了用到的几个struts ... -
Struts2标签库
2009-12-01 10:48 6505标签库,几乎是每个MVC ... -
Struts2的Result机制,让视图更丰富
2009-12-01 10:47 1653Struts2将Result列为一个独立的层次,可以说是整个S ... -
Struts2拦截器详解
2009-12-01 10:45 1905在之前的文章中,我们 ... -
Struts2MVC框架的困惑
2009-12-01 10:44 1189现在许许多多的初学者和程序员,都在趋之若鹜地学习Web开发的宝 ... -
Struts2配置详解
2009-12-01 10:43 876本篇文章让我们来详细探讨一下Struts2的配置文件的结构、配 ... -
Struts2的Action
2009-12-01 10:42 1045多数的MVC框架中的Control层,都是一个Java对象。按 ... -
Struts2参数传递
2009-12-01 10:41 2012本篇主要通过实例来讲述Struts2中各种各样的参数传递。这个 ... -
Struts2的ONGL
2009-12-01 10:38 1927先让我们花费1分钟的时 ... -
Struts2配置
2009-12-01 10:37 1252几乎所有的开源框架都 ... -
Struts2深入plugin
2009-12-01 10:36 814Struts2提供了一种非常灵活的扩展方式,这种被称之为plu ... -
Struts2开发环境的搭建
2009-12-01 10:32 918工欲善其事,必先利其器。在我们深入Struts2之前,我还是想 ... -
Struts2的学习方法
2009-12-01 10:30 1096正确的学习方法不仅能 ...
相关推荐
这篇博客文章可能详细探讨了如何在Struts2中使用OGNL来传递和操作数据。 OGNL是Struts2的核心组件之一,它允许开发者通过简单的字符串表达式来访问和修改对象的属性,甚至可以处理复杂的对象结构。以下是一些关于...
struts2 中 OGNL表达式的使用struts2 中 OGNL表达式的使用
2. **方法调用**:可以使用OGNL调用对象的方法,如`list.add("item")`。 3. **集合操作**:支持对集合进行操作,如`list[0]`访问列表的第一个元素,`map["key"]`访问映射中的值。 4. **运算符支持**:包括算术运算...
这个项目旨在帮助开发者理解和学习如何在Struts2中使用OGNL来操纵对象和数据。OGNL是Struts2中一个重要的组件,它允许在视图层和控制层之间传递和操作数据。 首先,我们来看`.classpath`、`.mymetadata`、`.project...
OGNL(Object-Graph Navigation Language)是Struts2框架中的一个重要组件,用于在Web应用中访问和操作Java对象的属性,调用其方法,以及执行类型转换等操作。 OGNL是对象图导航语言的缩写,它是一种功能强大的...
OGNL是Struts2的核心特性之一,Struts2使用OGNL来替代原先的EL表达式语言。Struts2将OGNL作为一个库集成到项目中,这使得Struts2在处理表单字段(如text field、hidden)方面更加灵活。与Struts1.x中的form bean相比...
1. **值栈访问**:Struts2使用值栈存储请求中的所有对象,OGNL可以从值栈顶部找到并访问对象。例如,`#request.user.name`表示从HTTP请求对象中获取`user`属性的`name`。 2. **动态方法调用**:OGNL支持直接调用...
OGNL(Object-Graph Navigation Language)是一种基于 Java 的表达式语言,Struts2 框架中使用 OGNL 来访问和操作 ValueStack 中的对象。在 Struts2 中,OGNL 是一个强大的工具,允许开发者访问和操作 ValueStack 中...
因此,在实际应用中,应确保对用户输入进行严格的校验和过滤,或者使用Struts2的安全插件来防止OGNL注入。 五、总结 OGNL在Struts2中扮演着关键角色,它简化了数据绑定和对象交互。然而,开发者也需要注意其潜在的...
Struts2是一个流行的Java web框架,它利用OGNL(Object-Graph Navigation Language)作为其核心表达式语言。OGNL是一种强大的表达式语言,允许开发者在Java对象之间导航和操作数据。在Struts2中,OGNL被广泛用于访问...
5. **安全特性**:在Struts2中,OGNL的不当使用可能导致安全漏洞,如著名的Struts2 OGNL注入攻击。源代码中包含了对这种风险的防护措施,如输入过滤和安全配置选项。 深入学习这些源代码,开发者不仅可以了解OGNL的...
在压缩包文件`struts-ognl.asta`中,可能包含了一些示例或测试用例,用于演示Struts2中PropertyAccessor的使用和功能。你可以通过分析这些文件来更深入地理解PropertyAccessor的工作原理。 总结起来,"struts2对...
在 Eclipse 3.4.1 中,你可以使用 OGNL 的源码进行调试和学习,这对于理解 OGNL 的工作原理和优化 Struts2 应用程序非常有帮助。你可以设置源码路径,以便在遇到 OGNL 相关的错误时查看其内部实现。 总的来说,...
### Struts2中OGNL的使用详解 #### 一、OGNL简介 OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取或设置一个对象图中的属性。它在Struts2框架中扮演着极其重要的角色,是Struts2实现...
- 表达式解析:Struts2使用OGNL来解析Action类中的属性值,将HTTP请求中的参数映射到Action对象的相应字段。 - 值栈:Struts2的值栈是一个存储Action对象和其他辅助对象的数据结构,OGNL可以方便地从值栈中查找和...
2. **值栈操作**:Struts2使用值栈存储请求相关的数据。OGNL可以直接访问值栈中的任何对象,例如`<s:property value="#session.user.name" />`将显示会话中用户对象的姓名。 3. **动态方法调用**:OGNL支持对对象的...
本篇文章将详细介绍Struts2中OGNL的使用,包括基本语法、表达式操作以及在实际开发中的应用。 ### OGNL简介 OGNL是一种强大的表达式语言,允许动态地访问和修改对象图。在Struts2中,OGNL负责视图层和模型层之间的...
OGNL(Object-Graph Navigation Language)是Struts2中的默认表达式语言,用于在视图和控制器之间传递数据。在这个主题中,我们将深入探讨Struts2与OGNL的整合以及它们在实际开发中的应用。 **Struts2框架概述** ...