要谈OGNL在Struts2中的应用,首先得明白OGNL到底是什么
在值栈中的对象,可以直接访问,但是用#.对象的时候却又访问不到,但用#this.对象的时候又可以访问得到,用%所有的没关系的
OGNL 的历史
OGNL 最初是为了能够使用对象的属性名来建立 UI 组件 (component) 和 控制器 (controllers) 之间的联系,简单来说就是:视图 与 控制器 之间数据的联系。后来为了应付更加复杂的数据关系,Drew Davidson 发明了一个被他称为 KVCL(Key-Value Coding Language) 的语言。 Luke 参与进来后,用 ANTLR 来实现了该语言,并给它取了这个新名字,他后来又使用 JavaCC 重新实现了该语言。目前 OGNL 由 Drew 来负责维护。目前很多项目中都用到了 OGNL,其中不乏为大家所熟知的,例如几个流行的 web 应用框架:WebWork【当然struts2也可以说是WebWork升级版】,Tapestry 等。
什么是 OGNL?
OGNL 是 Object-Graph Navigation Language 的缩写,从语言角度来说:它是一个功能强大的表达式语言,用来获取和设置 java 对象的属性 , 它旨在提供一个更高抽象度语法来对 java 对象图进行导航,OGNL 在许多的地方都有应用,例如:
1)作为 GUI 元素(textfield,combobox, 等)到模型对象的绑定语言。
2)数据库表到 Swing 的 TableModel 的数据源语言。
3)web 组件和后台 Model 对象的绑定语言 (WebOGNL,Tapestry,WebWork,WebObjects) 。
4)作为 Jakarata Commons BeanUtils 或者 JSTL 的表达式语言的一个更具表达力的替代语言。
另外,java 中很多可以做的事情,也可以使用 OGNL 来完成,例如:列表映射和选择。对于开发者来说,使用 OGNL,可以用简洁的语法来完成对 java 对象的导航。通常来说:通过一个“路径”来完成对象信息的导航,这个“路径”可以是到 java bean 的某个属性,或者集合中的某个索引的对象,等等,而不是直接使用 get 或者 set 方法来完成
OGNL 的基本语法
OGNL 表达式一般都很简单。虽然 OGNL 语言本身已经变得更加丰富了也更强大了,但是一般来说那些比较复杂的语言特性并未影响到 OGNL 的简洁:简单的部分还是依然那么简单。比如要获取一个对象的 name 属性,OGNL 表达式就是 name, 要获取一个对象的 headline 属性的 text 属性,OGNL 表达式就是 headline.text 。 OGNL 表达式的基本单位是“导航链”,往往简称为“链”。最简单的链包含如下部分:
表达式组成部分 示例
属性名称 如上述示例中的 name 和 headline.text
方法调用 hashCode() 返回当前对象的哈希码。
数组元素 listeners[0] 返回当前对象的监听器列表中的第一个元素。
所有的 OGNL 表达式都基于当前对象的上下文来完成求值运算,链的前面部分的结果将作为后面求值的上下文。你的链可以写得很长,例如:
name.toCharArray()[0].numericValue.toString()
上面的表达式的求值步骤:
提取根 (root) 对象的 name 属性。
调用上一步返回的结果字符串的 toCharArray() 方法。
提取返回的结果数组的第一个字符。
获取字符的 numericValue 属性,该字符是一个 Character 对象,Character 类有一个 getNumericValue() 方法。
调用结果 Integer 对象的 toString() 方法。
上面的例子只是用来得到一个对象的值,OGNL 也可以用来去设置对象的值。当把上面的表达式传入 Ognl.setValue() 方法将导致 InappropriateExpressionException,因为链的最后的部分(toString())既不是一个属性的名字也不是数组的某个元素。了解了上面的语法基本上可以完成绝大部分工作了。
OGNL 表达式
1)常量:字符串:“ hello ” 字符:‘ h ’ 数字:除了像 java 的内置类型 int,long,float 和 double,Ognl 还有如例:
0.01B,相当于 java.math.BigDecimal,使用’ b ’或者’ B ’后缀。 100000H,相当于 java.math.BigInteger,使用’ h ’ 或 ’ H ’ 后缀。
2)属性的引用例如:user.name
3)变量的引用例如:#name
4)静态变量的访问使用 @class@field
5)静态方法的调用使用 @class@method(args), 如果没有指定 class 那么默认就使用 java.lang.Math.
6)构造函数的调用例如:new java.util.ArrayList();
其它的 Ognl 的表达式可以参考 Ognl 的语言手册。
OGNL的性能
OGNL,或者说表达式语言的性能主要又两方面来决定,一个就是对表达式的解析 (Parser),另一个是表达式的执行,OGNL 采用 javaCC 来完成 parser 的实现,在 OGNL 2.7 中又对 OGNL 的执行部分进行了加强,使用 javasisit 来 JIT(Just-In-Time) 的生成 byte code 来完成表达式的执行。 Ognl 给这个功能的名字是:OGNL Expression Compilation 。基本的使用方法是:
SimpleObject root = new SimpleObject();
OgnlContext context = (OgnlContext) Ognl.createDefaultContext(null);
Node node = (Node) Ognl.compileExpression(context, root, "user.name");
String userName = (String)node.getAccessor().get(context, root);
表达式语言主要有以下几大好处:
1)避免(MyType) request.getAttribute()和myBean.getMyProperty()之类的语句,使页面更简洁;
2)支持运算符(如+-*/),比普通的标志具有更高的自由度和更强的功能;
3)简单明了地表达代码逻辑,使用代码更可读与便于维护。
Struts 2中的表达式语言
Struts 2支持以下几种表达式语言:
1)OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;
2)JSTL(JSP Standard Tag Library),JSP 2.0集成的标准的表达式语言;
3)Groovy,基于Java平台的动态语言,它具有时下比较流行的动态语言(如Python、Ruby和Smarttalk等)的一些起特性;
4)Velocity,严格来说不是表达式语言,它是一种基于Java的模板匹配引擎,具说其性能要比JSP好。
Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:
支持对象方法调用,如xxx.doSomeSpecial();
支持类静态的方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名 | 值名],例如:@java.lang.String@format('foo %s', 'bar')或@tutorial.MyConstant@APP_NAME;
支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;
访问OGNL上下文(OGNL context)和ActionContext;
操作集合对象。
Struts2中ONGL的使用示例
index.html
- <span style="font-size:18px;"><span style="font-size:18px;"><html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <meta http-equiv="refresh" content="0; url=ognl.action" />
- </head>
- </html></span></span>
User.java
- <span style="font-size:18px;"><span style="font-size:18px;">package com.javacrazyer.web.action;
- import java.util.Date;
- public class User {
- private Integer id;
- private String loginname;
- private Double score;
- private Boolean gender;
- private Character cha;
- private Date birthday;
- public User(){}
- public User(Integer id, String loginname, Double score, Boolean gender,
- Character cha, Date birthday) {
- this.id = id;
- this.loginname = loginname;
- this.score = score;
- this.gender = gender;
- this.cha = cha;
- this.birthday = birthday;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getLoginname() {
- return loginname;
- }
- public void setLoginname(String loginname) {
- this.loginname = loginname;
- }
- public Double getScore() {
- return score;
- }
- public void setScore(Double score) {
- this.score = score;
- }
- public Boolean getGender() {
- return gender;
- }
- public void setGender(Boolean gender) {
- this.gender = gender;
- }
- public Character getCha() {
- return cha;
- }
- public void setCha(Character cha) {
- this.cha = cha;
- }
- public Date getBirthday() {
- return birthday;
- }
- public void setBirthday(Date birthday) {
- this.birthday = birthday;
- }
- public String info() {
- return "User [birthday=" + birthday + ", cha=" + cha + ", gender="
- + gender + ", id=" + id + ", loginname=" + loginname
- + ", score=" + score + "]";
- }
- }</span></span>
OGNLAction.java
- <span style="font-size:18px;"><span style="font-size:18px;">package com.javacrazyer.web.action;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import org.apache.struts2.ServletActionContext;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
- public class OGNLAction extends ActionSupport {
- private static final long serialVersionUID = -2554018432709689579L;
- private String loginname;
- private String pwd;
- private User user;
- private Set<String> courseSet;
- private List<String> list;
- private Map<String,String> map;
- private List<User> userList;
- public String <span style="color:#000066;"><strong>execute()</strong></span> throws Exception{
- this.loginname = "xkkkkkkkkkkkkkkkkkkkkkkkk";
- this.user = new User(123, "wrr", 88.9, true, 'B', new Date());
- this.courseSet = new LinkedHashSet<String>();
- this.courseSet.add("corejava");
- this.courseSet.add("JSP/Servlet");
- this.courseSet.add("S2SH");
- this.list = new ArrayList<String>(this.courseSet);
- this.map = new HashMap<String, String>();
- this.map.put("x", "xxx");
- this.map.put("y", "yyy");
- this.map.put("z", "zzz");
- <span style="color:#993399;">ActionContext context = ActionContext.getContext();
- context.put("uname", "cheney");
- context.put("inte", Integer.valueOf(888888));
- context.put("user2", new User(123, "xxk", 88.9, true, 'B', new Date()));</span>
- this.userList = new ArrayList<User>();
- this.userList.add(new User(1, "zs", 48.9, true, 'D', new Date()));
- this.userList.add(new User(2, "ls", 68.1, true, 'C', new Date()));
- this.userList.add(new User(3, "ww", 78.2, false, 'B', new Date()));
- this.userList.add(new User(4, "zl", 88.3, true, 'A', new Date()));
- //-----------------------------------------------------------------
- //推荐方式:不会跟Servlet API耦合
- context.put("reqAtt", "往ActionContext中put的属性");
- context.getSession().put("sesAtt", "往ActionContext.getSession()中put的属性");
- context.getApplication().put("appAtt", "往ActionContext.getApplication()中put的属性");
- ServletActionContext.getRequest().setAttribute("reqAtt2", "Request作用域中的属性");
- ServletActionContext.getRequest().getSession().setAttribute("sesAtt2", "Session作用域中的属性");
- ServletActionContext.getServletContext().setAttribute("appAtt2", "Application作用域中的属性");
- return SUCCESS;
- }
- public String getAppName(){
- return "这是OGNL的使用示例代码";
- }
- public String getLoginname() {
- return loginname;
- }
- public void setLoginname(String loginname) {
- this.loginname = loginname;
- }
- public String getPwd() {
- return pwd;
- }
- public void setPwd(String pwd) {
- this.pwd = pwd;
- }
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this.user = user;
- }
- public Set<String> getCourseSet() {
- return courseSet;
- }
- public void setCourseSet(Set<String> courseSet) {
- this.courseSet = courseSet;
- }
- public List<String> getList() {
- return list;
- }
- public void setList(List<String> list) {
- this.list = list;
- }
- public Map<String, String> getMap() {
- return map;
- }
- public void setMap(Map<String, String> map) {
- this.map = map;
- }
- public List<User> getUserList() {
- return userList;
- }
- public void setUserList(List<User> userList) {
- this.userList = userList;
- }
- }</span></span>
src/struts.xml
- <span style="font-size:18px;"><span style="font-size:18px;"><%@ 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>
- <h3>OGNL的使用</h3><hr/>
- <span style="color:#6600cc;">访问Action中的普通属性</span>: <s:property value="loginname"/><br/>
- <span style="color:#ff6600;">访问Action中的对象属性</span>: <s:property value="user.birthday"/><br/>
- 访问Action中的Set属性: <s:property value="courseSet.toArray()[0]"/><br/>
- 访问Action中的List属性: <s:property value="list[0]"/><br/>
- 访问Action中的Map属性的键: <s:property value="map.keys.toArray()[1]"/><br/>
- 访问Action中的Map属性的值: <s:property value="map.values.toArray()[1]"/><br/>
- 访问Action中的Map属性的指定键对应的值: <s:property value="map['z']"/><br/>
- 访问Action中的Map属性的大小: <s:property value="map.size"/><br/>
- <hr/>
- 访问ActionContext中的普通属性:<s:property value="#inte"/><br/>
- 访问ActionContext中的对象属性:<s:property value="#user2.loginname"/><br/>
- <hr/>
- <strong><span style="color:#6600cc;">访问Action中的普通方法:<s:property value="getAppName()"/><br/></span></strong>
- 访问ActionContext中的某个对象上的普通方法:<s:property value="#user2.info()"/><br/>
- <hr/>
- <span style="color:#33cc00;">访问静态属性:<s:property value="@java.lang.Math@PI"/><br/>
- 访问静态方法:<s:property value="@java.lang.Math@floor(44.56)"/><br/></span>
- 访问Math类中的静态方法:<s:property value="@@floor(44.56)"/><br/>
- <hr/>
- <span style="color:#cc0000;">调用java.util.Date的构造方法</span>:<s:date name="new java.util.Date()" format="yyyy-MM-dd HH:mm:ss"/><br/>
- 调用java.util.Date的构造方法创建对象,再调用它的方法:<s:property value="new java.util.Date().getTime()"/><br/>
- <hr/>
- 投影查询:获取userList中所有loginname的列表:<s:property value="userList.{loginname}"/><br/>
- 选择查询:获取userList中所有score大于60的loginname列表:<s:property value="userList.{?#this.score>60.0}.{loginname}"/><br/>
- 选择查询:获取userList中所有score大于60并且gender为true的loginname列表:<s:property value="userList.{?(#this.score>60.0 && #this.gender)}.{loginname}"/><br/>
- 选择查询:获取userList中所有score大于60并且gender为true的第一个元素的loginname:<s:property value="userList.{^(#this.score>60.0 && #this.gender)}.{loginname}"/><br/>
- 选择查询:获取userList中所有score大于60并且gender为true的最后一个元素的loginname:<s:property value="userList.{$(#this.score>60.0 && #this.gender)}.{loginname}"/><br/>
- <hr/>
- 访问名为xxx的请求参数对应的第一个值:<s:property value="#parameters.xxx[0]"/><br/>
- 访问通过ActionContext中放入Request中的属性:<s:property value="#request.reqAtt"/><br/>
- 访问通过ServletActionContext中放入Request中的属性:<s:property value="#request.reqAtt2"/><br/>
- 访问通过ActionContext中放入Session中的属性:<s:property value="#session.sesAtt"/><br/>
- 访问通过ServletActionContext中放入Session中的属性:<s:property value="#session.sesAtt2"/><br/>
- 访问通过ActionContext中放入ServletContext中的属性:<s:property value="#application.appAtt"/><br/>
- 访问通过ServletActionContext中放入ServletContext中的属性:<s:property value="#application.appAtt2"/><br/>
- 直接访问属性域中指定名称的属性对应的值:<s:property value="#attr.sesAtt2"/><br/>
- <br/><br/><hr/>
- <s:iterator value="userList" status="vs">
- <s:if test="%{#vs.odd}">
- <span style="color: red">
- <s:property value="#vs.count"/>: <s:property value="loginname"/>,<s:date name="birthday" format="yyyy-MM-dd HH:mm:ss"/><br/>
- </span>
- </s:if>
- <s:else>
- <span style="color: blue">
- <s:property value="#vs.count"/>: <s:property value="loginname"/>,<s:date name="birthday" format="yyyy-MM-dd HH:mm:ss"/><br/>
- </span>
- </s:else>
- </s:iterator>
- <hr/><s:debug/>
- </body>
- </html></span></span>
总结:
在上边大家都好奇为什么都用struts的S标签,因为OGNL是通常要结合Struts 2的标志一起使用,如<s:property value="xx" />等
Action类与JSP页面之间的数据传递
1) 通过HttpServletRequest,HttpSession,ServletContext来传递数据。
a) Action中传数据:在Action类的请求处理方法中先获取各个作用域对象
ServletActionContext.getRequest();
ServletActionContext.getRequest().getSession();
ServletActionContext.getServletContext();
然后调用相应的setAttribute(String "键", Object 值);
b) 在JSP页面中取数据:可以使用EL表达式或代码片段来取出对应作用域中属性值。
c) 页面中的请求参数传递到Action中时,Action中直接定义对应名称的属性,并提供setter方法即可封装此数据。
2) 通过ActionContext实例来传递数据。 ActionContext针对每个正在执行Action的线程中绑定一份。
a) Action中通过ActionContext传递数据。
ActionContext提供了put(String "键", Object 值); //数据不会映射到HttpServletRequest中。
ActionContext提供的getSession().put(String "键", Object 值); //数据会自动映射到HttpSession中。
ActionContext提供的getApplication().put(String "键", Object 值); //数据会自动映射到ServletContext中。
b) 在JSP页面取数据:struts2推荐使用OGNL来取ActionContext中的数据。
1. Struts2中的OGNL的使用。
2. OGNL:对象图导航语言。通过OGNL表达式可以获取对象的属性,调用对象的方法,或构造出对象。
1) OGNL上下文中有一个根对象。这个根对象可以直接获取。不需要#。
2)支持常量:
字符串常量、字符常量、
数值常量:int、long、float、double
布尔常量:true、false
Null常量 : null
支持操作符:支持Java的所有操作符,还支持特有的操作符: ,、 {}、in、not in;
Struts2中的OGNL:
1) Struts2将ActionContext设置为OGNL上下文,并将值栈(ValueStack)作为OGNL的根对象放置到ActionContext中。
2) Struts2总是把当前Action实例放置在值栈的栈顶。所以,在OGNL中引用Action中的属性也可以省略“#”。
常用标签
1) <s:property value="OGNL"/>
2) <s:date name="OGNL" format=""/>
3) <s:if test="OGNL"></s:if><s:elseif test="OGNL"></s:elseif><s:else></s:else>
★4) <s:iterator value="OGNL" status="vs">...</s:iterator>
5) <s:debug/>
struts2中#、%和$这三个符号的使用方法【摘自max struts2教程】
一、"#"的用法
1、 访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:
parameters 包含当前HTTP请求参数的Map #parameters.id[0]作用相当于request.getParameter("id")
request 包含当前HttpServletRequest的属性(attribute)的Map #request.userName相当于request.getAttribute("userName")
session 包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName")
application 包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName")
attr 用于按request > session > application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止
2、用于过滤和投影(projecting)集合,如books.{?#this.price<100};
3、构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
二、"%"的用法
“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:
<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']" /></p>
<p><s:url value="%{#foobar['foo1']}" /></p>
三、"$"的用法
1、用于在国际化资源文件中,引用OGNL表达式
2、在Struts 2配置文件中,引用OGNL表达式
例如:
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action? albumId=${albumId}</result>
</action>
相关推荐
### Struts2中OGNL的使用详解 #### 一、OGNL简介 OGNL(Object-Graph Navigation Language)是一种强大的表达式语言,用于获取或设置一个对象图中的属性。它在Struts2框架中扮演着极其重要的角色,是Struts2实现...
2. **方法调用**:可以使用OGNL调用对象的方法,如`list.add("item")`。 3. **集合操作**:支持对集合进行操作,如`list[0]`访问列表的第一个元素,`map["key"]`访问映射中的值。 4. **运算符支持**:包括算术运算...
1. **值栈访问**:Struts2使用值栈存储请求中的所有对象,OGNL可以从值栈顶部找到并访问对象。例如,`#request.user.name`表示从HTTP请求对象中获取`user`属性的`name`。 2. **动态方法调用**:OGNL支持直接调用...
- **防范措施**:使用Struts2的安全插件如Struts2 Security Plugin来过滤和限制OGNL表达式的执行,或者启用OGNL的安全模式(Secure OGNL),避免执行危险的操作。 4. **源码分析** 阅读Struts2源码可以帮助理解...
OGNL(Object-Graph Navigation Language)是Struts2框架中的一个重要组件,用于在Web应用中访问和操作Java对象的属性,调用其方法,以及执行类型转换等操作。 OGNL是对象图导航语言的缩写,它是一种功能强大的...
OGNL(Object-Graph Navigation Language)是Struts2中的核心表达式语言,用于在Action对象和视图之间传递数据。在这个主题中,我们将深入探讨Struts2 OGNL2.6.11的源码,了解其内部工作原理和关键功能。 首先,...
struts2 中 OGNL表达式的使用struts2 中 OGNL表达式的使用
在提供的压缩包文件"Struts2_1900_OGNL"中,可能包含了一些关于Struts2 OGNL表达式使用和安全性的示例代码、教程文档或是漏洞分析。通过研究这些内容,你可以更深入地理解和掌握Struts2框架中OGNL表达式的运用,以及...
struts2 OGNL表达式使用 OGNL(Object-Graph Navigation Language)是对象图导航语言,允许开发者在Struts2应用程序中访问和操作对象及其属性。下面是OGNL表达式的使用方法: 访问基本属性 1. 访问值栈中action的...
这篇博客文章可能详细探讨了如何在Struts2中使用OGNL来传递和操作数据。 OGNL是Struts2的核心组件之一,它允许开发者通过简单的字符串表达式来访问和修改对象的属性,甚至可以处理复杂的对象结构。以下是一些关于...
5. **安全特性**:在Struts2中,OGNL的不当使用可能导致安全漏洞,如著名的Struts2 OGNL注入攻击。源代码中包含了对这种风险的防护措施,如输入过滤和安全配置选项。 深入学习这些源代码,开发者不仅可以了解OGNL的...
Struts2 OGNL表达式是Java Web开发中一个重要的概念,它是一种强大的对象图形导航语言(Object-Graph Navigation Language)。在Struts2框架中,OGNL被广泛用于视图层,作为数据绑定的主要手段,使得开发者能够方便...
这个"Struts2 OGNL示例(Maven项目)"提供了使用OGNL与Struts2集成的实例,帮助开发者更好地理解和应用这一强大的特性。 首先,让我们了解什么是OGNL。OGNL是一种强大的表达式语言,允许我们访问和修改对象图中的...
因此,在实际应用中,应确保对用户输入进行严格的校验和过滤,或者使用Struts2的安全插件来防止OGNL注入。 五、总结 OGNL在Struts2中扮演着关键角色,它简化了数据绑定和对象交互。然而,开发者也需要注意其潜在的...
Struts2 OGNL---标签详解析 都有实例 适合初学者
Struts2 OGNL语言学习笔记 OGNL(Object-Graph Navigation Language)是 Struts 2 中的一种表达式语言,主要用于简化 JSP 页面中的编码,使页面与后台代码分离。下面是 OGNL 语言的主要特点和用法: 1. 支持对象...
关于struts2 OGNL 详细教程,对初学者有帮助
本文将深入探讨OGNL的基本用法、标签的使用以及其在Struts2中的实际应用。 1. **OGNL基本概念** - OGNL是一种表达式语言,用于获取和设置对象属性。它支持点号和索引访问、方法调用、运算符、集合操作等。 - 例如...
5. **OGNL工具类(OGNLUtils)**:Struts2提供的辅助类,用于在框架中方便地使用OGNL,如`OGNLUtils.getValue(expression, context, root)`方法。 在Struts2帮助文档中,你会找到以下内容: 1. **基础用法**:包括...
然而,在Struts2的配置文件中,`$`通常不单独使用,而是与`{}`结合,形成`${expression}`这样的结构,用于在XML配置中嵌入OGNL表达式。例如,`${user.name}" />`将显示`user`对象的`name`属性的值。 在提供的文件...