struts2标签详解
A:
B:
C:
D:
E:
F:
G:
H:
I:
L:
M:
O:
P:
R:
S:
T:
U:
optiontransferselect标签属性
名字 |
数据类型 |
默 认 值 |
说明 |
addAllToLeftLabel |
String |
|
“全部添加到左边”按钮的行标 |
addAllToLeftOnclick |
String |
|
按下“全部添加到左边”按钮时将被调用的Javascript函数 |
addAllToRightLabel |
String |
|
“全部添加到右边”按钮的行标 |
addAllToRightOnclick |
String |
|
按下“全部添加到右边”按钮时将被调用的Javascript函数 |
addToLeftLabel |
String |
|
“添加到左边”按钮的行标 |
addToLeftOnclick |
String |
|
按下“添加到左边”按钮时将被调用的Javascript函数 |
addToRightLabel |
String |
|
“添加到右边”按钮的行标 |
addToRightOnclick |
String |
|
按下“添加到右边”按钮时 将被调用的Javascript函数 |
allowAddAllToLeft |
boolean |
true |
是否激活“全部添加到左边”按钮 |
allowAddAllToRight |
boolean |
true |
是否激活“全部添加到右边”按钮 |
allowAddToLeft |
boolean |
true |
是否激活“添加到左边”按钮 |
allowAddToRight |
boolean |
true |
是否激活“添加到右边”按钮 |
allowSelectAll |
boolean |
true |
是否激活“全选”按钮 |
allowUpDownOnLeft |
boolean |
true |
是否激活左侧select元素的“上下移动选项”按钮 |
allowUpDownOnRight |
boolean |
true |
是否激活右侧select元素的“上下移动选项”按钮 |
buttonCssClass |
String |
|
按钮的CSS类 |
buttonCssStyle |
String |
|
按钮的CSS样式 |
doubleCssClass |
String |
|
第二个选项列表的CSS类 |
doubleCssStyle |
String |
|
第二个选项列表的CSS样式 |
doubleDisabled |
boolean |
false |
是否禁用第二个选项列表 |
doubleEmptyOption |
boolean |
false |
是否要在第二个选项列表里插入 一个空白选项 |
doubleHeaderKey |
String |
|
第二个选项列表的标题的键 |
doubleHeaderValue |
String |
|
第二个选项列表的标题的键 |
doubleId |
String |
|
第二个选项列表的标识符 |
doubleList* |
String |
|
用来充当第二个选项列表的选 项来源的可遍历对象 |
doubleListKey |
String |
|
为第二个选项列表提供选项值的对象属性 |
doubleListValue |
String |
|
为第二个选项列表提供选项行标的对象属性 |
doubleMultiple |
boolean |
false |
是否允许用户在第二个选项列表里进行“多选多”选择 |
doubleName* |
String |
|
第二个组件的名字 |
doubleSize |
integer |
|
第二个选项列表的尺寸属性 |
emptyOption |
boolean |
false |
是否要在第一个选项列表里插入一个空白选项 |
formName |
String |
|
包含这个组件的表单的名字 |
headerKey |
String |
|
第一个选项列表里的标题的键 |
headerValue |
String |
|
第一个选项列表里的标题的值 |
leftDownLabel |
String |
|
左侧“下移”按钮上的文本 |
leftTitle |
String |
|
左侧select元素的名称 |
leftUpLabel |
String |
|
左侧“上移”按钮上的文本 |
list* |
String |
|
用来充当第一个选项列表的选项来源的可遍历对象 |
listKey |
String |
|
为第一个选项列表提供选项值的对象属性 |
listValue |
String |
|
为第一个选项列表提供选项行标的对象属性 |
multiple |
boolean |
|
是否允许用户在第一个选项列表里进行“多选多”选择 |
rightDownLabel |
String |
|
右侧“下移”按钮上的文本 |
rightTitle |
String |
|
右侧select元素的名称 |
rightUpLabel |
String |
|
右侧“上移”按钮上的文本 |
selectAllLabel |
String |
|
“全选”按钮上的文本 |
selectAllOnclick |
String |
|
按下“全选”按钮时将被调用的Javascript函数 |
size |
integer |
|
在第一个select元素里需要显示的选项的个数 |
updownOnLeftOnclick |
String |
|
按下左侧的“上移/下移”按钮时将被调用的Javascript函数 |
updownOnRightOnclick |
String |
|
按下右侧的“上移/下移”按钮时将被调用的Javascript函数 |
Struts2常用的Ajax标签
Struts2为了简化Ajax过程,提供了一些常用的Ajax标签,对于一些更复杂的Ajax通信过程,我们可以使用JSON插件来实现。
1,div标签
div标签在页面上生成一个div元素,但这个div元素的内容不是静态内容,而是从服务器获取的内容。必须为该div标签指定一个href属性,这个href属性必须是一个action,该action负责生成该div元素的内容。还可以指定该div标签生成的div元素以固定的频率来更新自身的内容,可以指定如下两个属性:
updateFreq:指定更新div的时间间隔,单位是ms,如果不指定,则只在页面加载时更新该div的内容。
delay:指定更新div内容的时间延迟,单位是ms,如果没有指定updateFreq属性,则该属性没有意义。
如果服务器包含了JavaScript代码,且希望在本页面内执行服务器响应的JavaScript代码,则可以为该div标签标签指定executeScripts="true"。
例子的页面代码如下:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>远程Divtitle>
<s:head theme="ajax"/>
head>
<body>
<s:url id="rd" value="/random.action" />
仅一次获取服务器内容的Div<br>
<s:div id="div1"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="%{rd}">
初始化文本
s:div>
动态更新内容的Div,每隔1s刷新一次(通过指定updateFreq="1000")<br>
使用indicator(通过指定indicator="indicator")<br>
<s:div id="div2"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="%{rd}"
updateFreq="1000"
indicator="indicator">
初始化文本
s:div>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/><br>
3s之后才开始更新(通过指定delay="3000")<br>
指定与服务器交互出错的提示(通过指定errorText属性)<br>
指定与服务器交互过程中的提示(通过指定loadText属性)<br>
<s:div id="div3"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="%{rd}" //使用变量来指定URL
updateFreq="1000"
delay="3000"
errorText="加载服务器数据出错"
loadingText="正在加载服务器内容">
初始化文本
s:div>
指定显示系统出错提示(通过指定showErrorTransportText="true")<br>
<s:div id="div4"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="/AjaxNoUrl.jsp"
updateFreq="1000"
showErrorTransportText="true"
loadingText="正在加载服务器内容">
初始化文本
s:div>
执行服务器脚本(通过指定executeScripts="true")
<s:url id="test" value="/Test3.action" />
<s:div id="div5"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="%{test}"
updateFreq="9000"
executeScripts="true"
loadingText="正在加载服务器内容">
初始化文本
s:div>
body>
html>
random.action的处理Action和JSP页面内容如下:
public class RandomAction implements Action {
private String data;
public String getRdmStr() {
String result = String.valueOf(Math.round(Math.random() * 10000));
return data != null && !data.equals("") ? data + result : result;
}
public void setData(String data) {
this.data = data;
}
public String getData() {
return this.data;
}
public String execute() {
return SUCCESS;
}
}
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
request.setAttribute("decorator", "none");
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
System.out.println("----------");
%>
服务器返回的随机数字是:
第二个Action是直接的JSP页面,页面包含JavaScript代码,页面内容如下:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
request.setAttribute("decorator", "none");
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>
<script language="JavaScript" type="text/javascript">
alert('Spring2.0宝典');
script>
轻量级J2EE企业应用实战
<script language="JavaScript" type="text/javascript">
alert('基于J2EE的Ajax宝典!');
script>
如果我们不需要该div调用远程Java方法,而是定期执行某个JavaScript函数,则可以为该div标签指定一个handler属性,该属性的值为该JavaScript函数。如下例子JSP页面代码:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>远程Divtitle>
<s:head theme="ajax"/>
head>
<script type="text/javascript">
function handler(widget, node) {
alert('本地JavaScript函数处理动态Div');
node.innerHTML = Math.random() > 0.4 ? "Spring2.0宝典" : "轻量级J2EE企业应用实战";
}
script>
<body>
<s:url id="rd" value="/random.action" />
直接使用本页面的JS函数,不再调用远程服务器<br>
<s:div id="div1"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="%{rd}" //此时的href属性无效
updateFreq="2000"
handler="handler">
初始化文本
s:div>
body>
html>
此外,div标签还可将一个表单里包含的表单域转换成对应的请求参数,并且把这些请求参数发送给远程服务器。为了让一个div标签发送表单里包含的表单域,可以为该div标签指定如下属性:
fromId:该属性的属性值为一个表单元素的ID,表明该div标签会把该表单里的表单域作为参数来发送。
为了通过在JavaScript代码中手动控制div标签启动自动更新,关闭自动更新,则可以为该div标签指定如下两个属性:
startTimerListenTopics:该属性设置一个监听的事件主题,当有Struts2组件向该主题发布事件时,该div标签的计时器被启动。
stopTimerListenTopics:该属性设置一个监听的事件主题,当有Struts2组件向该主题发布事件时,该div标签的计时器被关闭。
例子的JSP页面代码如下:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>远程Divtitle>
<s:head theme="ajax"/>
head>
<script>
var controller = {
refresh : function() {alert("手动刷新");},
start : function() {alert("启动自动刷新");},
stop : function() {alert("停止自动刷新");}
};
//将controller的refresh方法注册成/refresh主题的发布者
dojo.event.topic.registerPublisher("/refresh", controller, "refresh");
//将controller的start方法注册成/startTimer主题的发布者
dojo.event.topic.registerPublisher("/startTimer", controller, "start");
//将controller的stop方法注册成/stopTimer主题的发布者
dojo.event.topic.registerPublisher("/stopTimer", controller, "stop");
//为after主题指定一个事件处理函数
dojo.event.topic.subscribe("/after", function(data, type, e){
alert('与服务器交互过程中. 现在的过程类型是:' + type);
//data : text returned
//type : "before", "load" or "error"
//e : request object
});
script>
<body>
<form id="form">
<s:textfield name="data" label="输入框"/>
form>
<input type="button" value="手动刷新" onclick="controller.refresh()">
<input type="button" value="停止计时器" onclick="controller.stop()">
<input type="button" value="启动计时器" onclick="controller.start()">
<br>
<s:url id="rd" value="/random.action"/>
使用pub-sub机制(通过指定listenTopics等属性)<br>
发送表单请求参数(通过指定formId="form")<br>
<s:div id="div1"
theme="ajax"
cssStyle="border: 1px solid black;background-color:#dddddd;
width:300px;height:40px;padding-top:8px;padding-left:20px"
href="%{rd}"
loadingText="正在加载服务器内容"
listenTopics="/refresh" //加载服务器响应
startTimerListenTopics="/startTimer" //当有startTimer事件发布时启动计数器
stopTimerListenTopics="/stopTimer" //当有stopTimer事件发布是停止计数器
updateFreq="9000"
autoStart="true" //加载此页面时自动启动计数器
formId="form" //指定表单的ID
notifyTopics="/after"> //指定主题名为after,其它的事件都会发布到此主题下
初始化文本
s:div>
body>
html>
2,a和submit标签
a和submit标签的作用几乎完全一样,除了外在的表现不一样(a标签生成一个超链接,submit标签生成一个提交按钮)。它们都是用于向服务器发送异步请求,并将服务器响应加载在指定的HTML元素中,
href:指定单击这两个标签生成的超链接,按钮时发送请求的URL。
targets:该属性指定HTML元素的ID,该属性设置服务器响应来加载到该属性指定的几个HTML元素上。
executeScripts:设置是否执行远程的JavaScript代码。
handler:指定使用本页面的JavaScript函数作为按钮,超链接的单击事件处理函数,如果指定了此属性,则href属性无效。
此外,这两个标签也支持notifyTopics属性,把load事件发布到指定主题。
loadingText:当服务器响应还未成功装载时,targets属性指定的HTML标签显示的内容。
errorText:当与服务器交互之间存在错误时,targets属性指定的HTML标签显示的内容。
form:设置将form属性指定的表单的表单域作为请求参数发送到服务器。
下面是a标签的例子JSP页面代码:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>远程链结title>
<s:head theme="ajax"/>
head>
<script type="text/javascript">
function before() {alert("before request");}
function after() {alert("after request");}
function handler(widget, node)
{
alert('本地自定义函数');
dojo.byId(widget.targetsArray[0]).innerHTML = "Spring2.0宝典";
}
dojo.event.topic.subscribe("/after", function(data, type, e){
alert('正处于Dojo的异步交互过程中,类型是:'+type);
//data : text returned
//type : "before", "load" or "error"
//e : request object
});
script>
<body>
<div id="t1" style="background-color:#bbbbbb;width:360px;height:80px">Div 1div>
<br/>
<div id="t2" style="background-color:#bbbbbb;width:360px;height:80px">Div 2div>
<br/>
<s:url id="ajaxTest" value="/AjaxTest.action" />
<s:url id="test3" value="/Test3.action" />
<br/>
同时修改Div1和Div2的内容<br/>
且将事件发布到/after主题(指定notifyTopics属性)<br/>
<s:a id="link1"
theme="ajax"
href="%{ajaxTest}"
indicator="indicator"
targets="t1,t2" notifyTopics="/after" >修改Div1和Div2内容s:a>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<br/>
指定服务期返回失败时的错误提示(指定errorText属性)<br/>
因为系统中AjaxNoUrl.jsp页面不存在,肯定出错!<br/>
<s:a id="link2"
theme="ajax"
href="/AjaxNoUrl.jsp"
errorText="系统服务器返回信息出错"
targets="t1">修改'Div 1'内容,使用自定义出错提示s:a>
<br/>
指定系统加载中的提示信息(指定loadingText属性)<br/>
<s:a id="link3"
theme="ajax"
href="%{ajaxTest}"
loadingText="系统正在加载中"
targets="t1">修改'Div 1'内容,使用自定义加载信息s:a>
<br/>
执行远程JavaScript代码(指定executeScripts=true属性)<br/>
<s:a id="link4"
theme="ajax"
href="%{test3}"
executeScripts="true"
targets="t2">接执行远程JavaScripts:a>
<br/>
通过使用自定义JavaScript函数来实现Ajax交互(指定handle属性)<br/>
<s:a id="link5"
theme="ajax"
href="%{ajaxTest}"
handler="handler"
targets="t2">使用自定义的处理函数s:a>
<form id="form">
<input type=textbox name="data">
form>
提交表单请求(通过指定formId属性)
<s:a id="link6"
theme="ajax"
href="%{ajaxTest}"
targets="t2"
formId="form">Div 2 会显示在上面文本框中输入的内容s:a>
body>
html>
Action和JSP页面代码如下:
public class AjaxTestAction implements Action, Serializable
{
private static int counter = 0;
private String data;
public long getServerTime()
{
return System.currentTimeMillis();
}
public int getCount()
{
return ++counter;
}
public String getData()
{
return "服务器提示:" + data;
}
public void setData(String data)
{
this.data = data;
}
public String execute() throws Exception
{
return SUCCESS;
}
}
JSP页面:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
request.setAttribute("decorator", "none");
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>
服务器计数器: <s:property value="count"/><br>
当前时间是:<s:property value="serverTime"/><br>
服务器返回的提示是:<s:property value="data"/>
JSP页面2:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%
request.setAttribute("decorator", "none");
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>
<script language="JavaScript" type="text/javascript">
alert('Spring2.0宝典');
script>
轻量级J2EE企业应用实战
<script language="JavaScript" type="text/javascript">
alert('基于J2EE的Ajax宝典!');
script>
下面是使用submit标签的例子代码:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>远程按钮title>
<s:head theme="ajax" debug="true"/>
head>
<script type="text/javascript">
dojo.event.topic.subscribe("/after", function(data, type, e){
alert('正处于Dojo的异步交互过程中,类型是:'+type);
//data : text returned
//type : "before", "load" or "error"
//e : request object
});
script>
<body>
<div id="t1" style="background-color:#bbbbbb;width:360px;height:80px">将被改变的结果div>
<s:url id="ajaxTest" value="/AjaxTest.action" />
简单的提交按钮,使用indicator<br>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<s:submit type="submit" theme="ajax" value="提交" targets="t1" href="%{ajaxTest}" align="left" indicator="indicator"/>
<br/>
简单的提交按钮,使用pub-sub事件模型(设置notifyTopics=/after属性)<br>
<s:submit type="submit" theme="ajax" value="提交" targets="t1" href="%{ajaxTest}" align="left" notifyTopics="/after"/>
<br/>
图片按钮(通过指定type="image")<br>
<s:submit type="image" theme="ajax" label="Alt Text" targets="t1"
src="${pageContext.request.contextPath}/images/struts-power.gif" href="%{ajaxTest}" align="left" />
<br/>
异步方式提交表单:(在下面输入的文本将在上面显示)
<s:form id="form" action="AjaxTest">
<input type="text" name="data"/>
<s:submit type="button" theme="ajax" label="发送" targets="t1" id="ajaxbtn"/> //会发送from中的参数
s:form>
body>
html>
实际上,使用submit标签有两种用法,一是指定formID属性,二是在form标签内部使用submit标签。
3,autocompleter标签
autocompleter标签会生成一个带下拉按钮的单行文本输入框,当用户单击下拉按钮时,将看到一系列的选项,单击某个选项时可以将该选项填入单行文本框.
下拉选择框的选项会在页面加载时自动加载,而且随着用户在单行广西框中输入时改变,当用户输入字符串时,下拉列表框的选项总是和单行文本框中内容以某种方式匹配.此时,用户也可以通过上,下箭头来选择合适的选项,并将指定选项填入单行文本框.
如果我们设置autocompleter标签的autoComplete=true(默认是false),该标签将会在单行文本框中生成输入提示.如果希望强制用户只能输入下拉列表中的列表项,则可以设置forceValidOption=true(默认是false).
该标签有如下几个属性:
autoComplete:设置是否在单行文本输入框中显示提示输入
forceValidOption:设置单行文本框内是否只接受下拉列表中列表项
delay:指定显示下拉列表框之前的延迟时间
href:指定异步生成下拉列表项的URL
searchType:设置下拉列表项与单行文本框的字符串的匹配模式,可以接受3个值:startstring(显示以文本框中字符串开头的选项,这是默认值);startword(显示以文本框中单词开头的选项);substring(显示包含文本框中字符串的选项).
dropdownHeight:设置下拉列表框的高度,默认是120
dropdownWidth:设置下拉列表框的宽度,默认与单行文本框的宽度相同.
formId:指定发送哪个表单里的表单域的请求参数
value:当theme使用simple时,指定该标签的默认值
list:指定用于迭代生成下拉选项的集合
loadOnTextChange:设置当用户在单行文本框内输入时,是否重新加载列表项.
loadMinimumCount:当loadOnTextChange属性设置为true时,该属性设置输入多少字符后,才会触发重新加载列表项.
showDownArrow:是否显示下拉箭头,默认是显示.
因为autocompleter标签要求服务器响应可以被解析成下拉列表项,而autocompleter是使用JSON格式来解析服务器响应的,因此,要求服务器响应必须是如下格式:
[
["Spring2.0宝典"],
["轻量级J2EE企业实战"],
["基于J2EE的Ajax宝典"]
]
上面的服务器响应将被解析成两个选项,第一个是显示文本的display Text1,对应的值是value1;第二是显示文本的display Text2,对应的值是value2.
下面是使用autocompleter的例子JSP页面代码:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>自动完成title>
<s:head theme="ajax" debug="true"/>
head>
<body>
<s:url id="books" value="/books.action"/>
服务器(/books.action)总是返回一个简单的JSON list。<br>
不使用自动完成(autoComplete="false")。<br>
使用indicator<br>
字符串匹配模式是子串匹配(searchType="substring")<br>
<s:autocompleter name="book" theme="ajax" indicator="indicator1" href="%{books}"
cssStyle="width: 200px;"
autoComplete="false"
searchType="substring"/>
<img id="indicator1" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<br/>
用户输入时重新加载下拉列表项(loadOnTextChange="true")<br>
当3个字符后才触发重新加载下拉列表(loadMinimumCout="3")<br>
不出现下拉箭头 (showDownArrow="false")<br>
<s:autocompleter theme="ajax" indicator="indicator" href="%{books}" cssStyle="width: 200px;" autoComplete="false" loadOnTextChange="true" loadMinimumCount="3" showDownArrow="false"/>
<img id="indicator" src="${pageContext.request.contextPath}/images/indicator.gif" alt="Loading" style="display:none"/>
<br/>
设置在文本框中提示自动完成(autoComplete="true")。<br>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" autoComplete="true" />
<br/>
使用本页面的集合来自动完成
<br/>
<s:autocompleter theme="simple" list="{'Spring2.0宝典','轻量级J2EE企业实战','基于J2EE的Ajax宝典'}" cssStyle="width: 240px;"/>
<br/>
校验用户输入,强制只能输入下拉列表项(forceValidOption="true")
<br/>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" forceValidOption="true"/>
<br/>
设置dropdown的高度是180px (dropdownHeight="180")
<br/>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" dropdownHeight="180"/>
<br/>
禁用combobox功能 (disabled="true")
<br/>
<s:autocompleter theme="ajax" href="%{books}" cssStyle="width: 200px;" disabled="true"/>
body>
html>
此页面请求的action直接返回一个文件,文件内容为:(国际化后的数据内容)
[
["Spring2.0\u5b9d\u5178"],
["\u8f7b\u91cf\u7ea7J2EE\u4f01\u4e1a\u5b9e\u6218"],
["\u57fa\u4e8eJ2EE\u7684Ajax\u5b9d\u5178"]
]
此外还可以使用autocompleter标签进行异步提交表单,异步提交同样有两种方式:1,为autocompleter标签指定formId属性,该属性指向需要异步提交的表单ID;2,将autocompleter标签放在form标签下使用。
下面代码是实现两个autocompleter标签的关联,第二个autocompleter的选项内容将根据第一个autocompleter标签的请求参数来重新加载选项。因此将第一个autocompleter的事件注册成某个事件主题的发布者,将第二个autocompleter的事件注册成该事件的订阅者。例子JSP页面代码如下:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>自动完成title>
<s:head theme="ajax" debug="true"/>
head>
将两个关联起来
<br/>
<form id="selectForm">
请选择您喜欢的作者:<br>
<s:autocompleter theme="simple" name="author"
list="{'李','Rod Johnson' , 'David Flanagan'}"
value="李" notifyTopics="/book"
forceValidOption="true"
id="sel"/>
form>
请选择您喜欢的图书:<br>
<s:url id="getBook" value="/getBook.action"/>
<s:autocompleter theme="ajax" href="${getBook}" cssStyle="width: 240px;"
autoComplete="false" formId="selectForm" listenTopics="/book" forceValidOption="true" id="ops"/>
body>
html>
Action代码如下:
public class GetBookAction extends ActionSupport {
private String author;
private List
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public List
return books;
}
public String execute() throws Exception {
System.out.println(author);
if (author.equals("李")) // 这里是用"李"的unicode码来作比较,因为Dojo采用了unicode码来处理
{ // 所有的非西欧字符,Struts2是建立在Dojo基础上的。
books.clear();
books.add("Spring2.0宝典");
books.add("轻量级J2EE企业应用实战");
books.add("基于J2EE的Ajax宝典");
} else if (author.equals("Rod Johnson")) {
books.clear();
books.add("Expert One-on-One J2EE Design and Development");
} else if (author.equals("David Flanagan")) {
books.clear();
books.add("JavaScript权威指南");
}
return SUCCESS;
}
}
Action返回的数据页面代码如下:
<%@ page contentType="text/html;charset=GBK" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
[
["
]
struts2中非表单标签的使用
非表单标签主要用于在页面生成一些非表单的可视化元素,例如Tab页面,输出HTML页面的树形结构等。当然,非表单标签也包含在页面显示Action里封装的信息。非表单标签主要有如下几个:
a:生成一个超级连接(link)
actionerror:如果Action实例的getActionErrors()方法返回不为null,则该标签负责输出该方法返回的系列错误。
actionmessage :如果Action实例的getActionMessages()方法返回不为null,则该标签负责输出该方法返回的系列消息。
component:使用此标签可以生成一个自定义组件。
div :此标签负责生成一个div片段。
fielderror:如果Action实例存在表单域的类型转换错误、校验错误,该标签负责输出这些错误提示。
tabbedPanel:生成HTML页面的Tab页。
tree:生成一个树形结构。
treenode:生成树形结构的节点。
下面,使用上面列出的一些十分常用的非表单标签。
1. actionerror和actionmessage标签
这两个标签用法完全一样,作用也几乎完全一样,都是负责输出Action实例里封装的信息,区别是actionerror标签负责输出Action实例的getActionError()方法的返回值,而actionmessage标签负责输出Action实例的getActionMessage()方法的返回值。对于这两个标签而言,几乎没有自己的专有属性,故使用起来非常简单。下面是本示例应用中的Action类,这个Action类仅仅添加了两条ActionError和ActionMessage,并没有做过多处理,代码:
public class DemoAction extends ActionSupport {
public String execute() {
// 添加两条Error信息
addActionError("第一条错误消息!");
addActionError("第二条错误消息!");
// 添加两条普通信息
addActionMessage("第一条普通消息!");
addActionMessage("第二条普通消息!");
return SUCCESS;
}
}
上面的Action的execute方法仅仅在添加了四条消息后,直接返回success字符串,success字符串对应的JSP页面中使用
<s:actionerror/>
<s:actionmessage />
在另一个页面中使用
从上面的
2. component标签
component标签用于使用自己的自定义组件,这是一个非常灵活的用法,如果经常需要使用某个效果片段,就可以考虑将这个效果片段定义成一个自定义组件,然后在页面中使用component标签来使用该自定义组件。因为使用自定义组件还是基于主题、模板管理的,因此在使用component标签时,常常需要指定如下三个属性:
theme:自定义组件所使用的主题,如果不指定该属性,默认使用xhtml主题。q
qtemplateDir:指定自定义组件的主题目录,如果不指定,默认使用系统的主题目录,即template目录。
qtemplate:指定自定义组件所使用的模板。
除此之外,还可以在cmponent标签内使用param子标签,子标签表示向该标签模板中传入额外的参数。如果希望在模板中取得该参数,总是采用如下形式:$parameters.paramname,或者$parameters['paramname']。
提示:自定义的模板文件可以采用FreeMarker、JSP和Velocity三种技术来书写。
看下面的JSP页面,该页面多次使用了
使用自定义主题,自定义主题目录<br>
从Web应用根路径下加载模板,使用ftl模板。
<s:component
theme="customTheme"
templateDir="customTemplateDir"
template="ftlCustomTemplate">
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EE的Ajax宝典'}" />
s:component>
<hr/>
使用自定义主题,自定义主题目录<br>
从Web应用根路径下加载模板,使用JSP模板。
<s:component
theme="customTheme"
templateDir="customTemplateDir"
template="jspCustomTemplate.jsp">
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EE的Ajax宝典'}" />
s:component>
<hr/>
使用默认主题(xhtml),默认主题目录(template)<br>
从Web应用中加载模板,使用JSP模板。
<s:component template="mytemplate.jsp">
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EE的Ajax宝典'}" />
s:component>
<hr/>
使用自定义主题,自定义主题目录<br>
从/WEB-INF/classes路径下加载模板,使用ftl模板。
<s:component
theme="myTheme"
templateDir="myTemplateDir"
template="myAnotherTemplate">
<s:param name="list" value="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , '基于J2EE的Ajax宝典'}" />
s:component>
在上面页面中使用了2个FreeMarker模板,这两个FreeMarker模板都使用了FreeMarker标签。除此之外,本页面中还使用了两个JSP模板,这两个JSP页面只是加载的位置不同,两个模板的代码是相同的,下面是JSP模板的代码:
<%@ page contentType="text/html; charset=GBK" language="java"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<div style="background-color:#eeeeee;">
<b>JSP自定义模板<br>
请选择您喜欢的图书<br>b>
<s:select list="parameters.list"/>
div>
3. tree和treenode初步
这里仅仅介绍tree和treenode标签的初步用法,我们可以通过tree和treenode在页面中生成一个树形结构。其中tree生成一个树形结构,treenode生成一个树节点。
对于tree和treenode标签,都可指定一个label属性,该属性指定了树、或者树节点的标题。看如下代码:
<s:tree label="计算机图书" id="book" theme="ajax"
showRootGrid="true" showGrid="true" treeSelectedTopic="treeSelected">
<s:treenode theme="ajax" label="李刚" id="yeeku">
<s:treenode theme="ajax" label="Spring2.0宝典" id="spring"/>
<s:treenode theme="ajax" label="轻量级J2EE企业应用实战" id="lightweight"/>
<s:treenode theme="ajax" label="基于J2EE的Ajax宝典" id="ajax"/>
s:treenode>
<s:treenode theme="ajax" label="David" id="David">
<s:treenode theme="ajax" label="JavaScript: The Definitive Guide" id="javascript"/>
s:treenode>
<s:treenode theme="ajax" label="Johnson" id="Johnson">
<s:treenode theme="ajax" label="Expert One-on-One J2EE Design and Development" id="j2ee"/>
s:treenode>
s:tree>
从上面代码中可以看出,所有的treenode标签必须放在tree标签内部,或者放在treenode标签的内部。当放在tree标签的内部时,该节点是该树的根节点,当放在treenode标签的内部时,它是该节点的子节点。
Strus2的表单标签的使用
Struts2为大家提供了不少常用的很酷的表单标志,简化了我们程序员的工作。不过,由于这些都是新标志,大家可能在使用上还存在不少疑问。本文将就朋友们的回复、留言或Email上的问题,分别对这些酷标志进行讲述。
Struts 2的表单标志在输出(render)HTML时,使用了模板的概念,增加了复杂性(因为它不像Struts 1.x的表单标志,它通常都是一个标志对应HTML的一个元素),因此大家在使用时,需要一些技巧:
下面我将分别对这些标志进行讲述:
大家对
答案其实很简单,只需要将其“value”属性设为你的要选中的值,如以代码所示:
<%@page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8" %>
<%@taglib prefix="s" uri="/struts-tags" %>
DOCTYPE html PUBLIC"-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 Cool Tags - <s:checkboxlist/ >title>
<s:head />
head>
<body>
<h2><s:checkboxlist/>h2>
<s:form action="Store">
<s:checkboxlistname="skills1"
label="Skills 1"
list="{ 'Java', '.Net', 'RoR', 'PHP' }"
value="{ 'Java', '.Net' }"/>
<s:checkboxlistname="skills2"
label="Skills 2"
list="#{ 1:'Java', 2: '.Net', 3: 'RoR', 4:'PHP' }"
listKey="key"
listValue="value"
value="{ 1, 2, 3 }"/>
s:form>
body>
html>
清单1 WebContent/checkboxlist.jsp
分布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/checkboxlist.jsp,出现如下图所示页面:
清单2 checkboxlist.jsp页面
大家看Struts 2的showcase的例子,
<s:doubleselect
tooltip="Choose Your State"
label="State"
name="region" list="{'North', 'South'}"
value="'South'"
doubleValue="'Florida'"
doubleList="top== 'North' ? {'Oregon', 'Washington'}: {'Texas', 'Florida'}"
doubleName="state"
headerKey="-1"
headerValue="----------Please Select ----------"
emptyOption="true"/>
清单3 Showcase中
很多朋友问:“上面的‘list’属性只有两个值,如果我有三个或更多的值,‘doublelist’属性应该如何设定呢?”
我建议的做法是先定义一个Map类型的对象,键为“list”的集合,值则为“doubleList”的集合,然后“doubleList”的OGNL写成“#myMap[top]”,如以下代码所示:
<%@page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8" %>
<%@taglib prefix="s" uri="/struts-tags" %>
DOCTYPE html PUBLIC"-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 Cool Tags - <s:doubeselect/ >title>
<s:head />
head>
<body>
<h2><s:doubleselect/>h2>
<s:form action="Store">
<s:setname="foobar"
value="#{'Java': {'Spring', 'Hibernate', 'Struts 2'}, '.Net': {'Linq',' ASP.NET 2.0'}, 'Database': {'Oracle', 'SQL Server', 'DB2', 'MySQL'}}"/>
<s:doubleselectlist="#foobar.keySet()"
doubleName="technology"
doubleList="#foobar[top]"
label="Technology"/>
s:form>
body>
html>
清单4 WebContent/doubleselect.jsp
分布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/doubleselect.action,出现如下图所示页面:
清单5 doubleselect.jsp页面
这个标志可能大家不常用,不过本人认为它还是挺有用的。在使用Struts1.x时,因为跳转通常是用Forward(而不是Redirect)实现的,所以当用户完成请求后,按“F5”刷新页面时,就会重新提交上次的请求,这样经常会出错。要解决这个问题,
在页面加载时,
<input type="hidden" name="struts.token.name" value="struts.token"/>
<input type="hidden" name="struts.token" value="BXPNNDG6BB11ZXHPI4E106CZ5K7VNMHR"/>
清单6
同时,将GUID放到会话(session)中;在执行action之前,“token”拦截器将会话token与请求token比较,如果两者相同,则将会话中的token删除并往下执行,否则向actionErrors加入错误信息。如此一来,如果用户通过某种手段提交了两次相同的请求,两个token就会不同。
首先看一下Action的代码:
package tutorial;
import com.opensymphony.xwork2.ActionSupport;
publicclass CoolTagAction extends ActionSupport {
privatestaticfinallong serialVersionUID = 6820659617470261780L;
private String message;
public String getMessage() {
return message;
}
publicvoid setMessage(String message) {
this.message = message;
}
@Override
public String execute() {
System.out.println("Executing action, your message is " +message);
return SUCCESS;
}
}
清单7 src/tutorial/CoolTagAction.java
以上代码一目了然,再看看JSP的写法:
%@ page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" %>
<%@taglib prefix="s" uri="/struts-tags" %>
DOCTYPE html PUBLIC"-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 Cool Tags - <s:token/ >title>
<s:head />
head>
<body>
<h2><s:token/>h2>
<s:actionerror />
<s:form action="Token">
<s:textfieldname="message" label="Message"/>
<s:token/>
<s:submit/>
s:form>
body>
html>
清单8 WebContent/token.jsp
JSP也很简单,就是加入
xml version="1.0"encoding="UTF-8"?>
DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="Struts2_COOL_TAGS_DEMO" extends="struts-default">
<actionname="Token" class="tutorial.CoolTagAction">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="token"/>
<result name="invalid.token">/token.jspresult>
<result>/token.jspresult>
action>
<actionname="*">
<result>/{1}.jspresult>
action>
package>
struts>
清单9 src/struts.xml
以上XML片段值注意的是加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话token与请求token不一致时,将会直接返回“invalid.token”结果。
发布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/token.jsp,出现如下图所示页面:
清单10 正常显示的token.jsp页面
随便填点东西并提交页面,一切正常返回以上页面,然后按“F5”刷新页面,在弹出的对话框中点击“Retry”,出现如下图所示页面:
清单11 重复提交出错显示
这几个标志的使用相对简单,所以我想小举一例即可,以下是JSP的代码:
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 Cool Tags - Otherstitle>
<s:head />
head>
<body>
<h2>Othersh2>
<s:form action="Store">
<s:datetimepickername="birthday" label="Birthday"/>
<s:updownselect
label = "Favourite Countries"
list="#{'england':'England','america':'America', 'germany':'Germany'}"
name="prioritisedFavouriteCountries"
headerKey="-1"
headerValue="---Please Order Them Accordingly ---"
emptyOption="true"/>
<s:optiontransferselect
label="Favourite Cartoons Characters"
name="leftSideCartoonCharacters"
leftTitle="LeftTitle"
rightTitle="RightTitle"
list="{'Popeye','He-Man', 'Spiderman'}"
multiple="true"
headerKey="headerKey"
headerValue="---Please Select ---"
emptyOption="true"
doubleList="{'Superman','Mickey Mouse', 'Donald Duck'}"
doubleName="rightSideCartoonCharacters"
doubleHeaderKey="doubleHeaderKey"
doubleHeaderValue="--- Please Select ---"
doubleEmptyOption="true"
doubleMultiple="true"/>
s:form>
body>
html>
清单12 WebContent\others.jsp页面
发布运行应用程序,在浏览器中键入:http://localhost:8080/Struts2_CoolTags/others.jsp,出现如下图所示页面:
清单13 其它表单标志页面
Struts 2在标志上的确比Struts1.x丰富了许多,同时模板机制也给程序员带来不少方便(如果你不太喜欢个性化的风格)。另外,Struts 2还有一些AJAX(如
Struts2在OGNL基础上的增强
1、值栈(ValueStack)
Struts2将OGNL上下文设置为Struts2中的ActionContext(内部使用的仍然是OgnlContext),并将值栈设为OGNL的根对象。
我们知道,OGNL上下文中的根对象可以直接访问,不需要使用任何特殊的“标记”,而引用上下文中的其他对象则需要使用“#”来标记。由于值栈是上下文中的根对象,因此可以直接访问。那么对于值栈中的对象该如何访问呢?Struts2提供了一个特殊的OGNLPropertyAccessor,它可以自动查找栈内的所有对象(从栈顶到栈底),直接找到一个具有你所查找的属性的对象。也就是说,对于值栈中的任何对象都可以直接访问,而不需要使用“#”。
假设值栈中有两个对象:student和employee,两个对象都有name属性,student有学号属性number,而employee有薪水属性salary。employee先入栈,student后入栈,位于栈顶,那么对于表达式name,访问的就是student的name属性,因为student对象位于栈顶;表达式salary,访问的就是employee的salary属性。正如你所见,访问值栈中的对象属性或方法,无须指明对象,也不用“#”,就好像值栈中的对象都是OGNL上下文中的根对象一样。这就是Struts2在OGNL基础上做出的改进。
2、[N]语法
如上所述,如果想要访问employee的name属性,应该如何写表达式呢?我们可以使用[N].xxx(N是从0开始的整数)这样的语法来指定从哪一个位置开始向下查找对象的属性,表达式[1].name访问的就是employee对象的name属性。
在使用[N].xxx语法时,要注意位置序号的含义,它并不是表示“获取栈中索引为N的对象”,而是截取从位置N开始的部分栈。
3、top关键字
top用于获取栈顶的对象,结合[N].xxx语法,我们就可以获取栈中任意位置的对象。
如:[0].top,[1].top等
4、访问静态成员
除了使用标准的OGNL表达式访问静态字段和静态方法外,Struts2还允许你不指定完整的类名,而是通过“vs”前缀来调用保存在栈中的静态字段和静态方法。
@vs@FOO_PROPERTY
@vs@someMethod()
@vs1@someMethod()
vs表示ValueStack,如果只有vs,那么将使用栈顶对象的类;如果在vs后面跟上一个数字,那么将使用栈中指定位置处的对象类。
5、值栈中的Action实例
Struts2框架总是把Action实例放在栈顶。因为Action在值栈中,而值栈又是OGNL中的根,所以引用Action的属性可以省略“#”标记,这也是为什么我们在结果页面中可以直接访问Action的属性的原因。
6、Struts2中的命名对象
Struts2还提供了一些命名对象,这些对象没有保存在值栈中,而是保存在ActionContext中,因此访问这些对象需要使用“#”标记。这些命名对象都是Map类型。
parameters
用于访问请求参数。如:#parameters['id']或#parameters.id,相当于调用了HttpServletRequest对象的getParameter()方法。
注意,parameters本质上是一个使用HttpServletRequest对象中的请求参数构造的Map对象,一量对象被创建(在调用Action实例之前就已经创建好了),它和HttpServletRequest对象就没有了任何关系。
request
用于访问请求属性。如:#request['user']或#request.user,相当于调用了HttpServletRequest对象的getAttribute()方法。
session
用于访问session属性。如:#session['user']或#session.user,相当于调用了HttpSession对象的getAttribute()方法。
application
用于访问application属性。如:#application['user']或#application.user,相当于调用了ServletContext的getAttribute()方法。
attr
如果PageContext可用,则访问PageContext,否则依次搜索request、session和application对象。
struts2标签详解
要在jsp中使用Struts2的标志,先要指明标志的引入。通过jsp的代码的顶部加入以下的代码:
<%@taglib prefix="s" uri="/struts-tags" %>
If elseif else
描述:
执行基本的条件流转。
参数:
名称 |
必需 |
默认 |
类型 |
描述 |
备注 |
test |
是 |
|
boolean |
决定标志里的内容是否显示的表达式 |
else标志没有这个参数 |
id |
否 |
|
Object/String |
用来标识元素的id。在UI和表单中为HTML的id属性 |
|
例子:
<s:set name="age" value="61"/>
<s:if test="${age > 60}">
老年人
s:if>
<s:elseif test="${age> 35}">
中年人
s:elseif>
<s:elseif test="${age> 15}"id="wawa">
青年人
s:elseif>
<s:else>
少年
s:else>
<s:set name="name" value="<%="'"+ request.getParameter("name")+"'"%>"/>
<%
System.out.println(request.getParameter("name"));
%>
<s:if test="#name=='zhaosoft'">
zhaosoft here
s:if>
<s:elseif test="#name=='zxl'">
zxl here
s:elseif>
<s:else>
other is here
s:else>
Iterator(迭代)
描述:用于遍历集合(java.util.Collection)或枚举值(java.util.iterator)
参数
名称 |
必需 |
默认 |
类型 |
描述 |
status |
否 |
|
String |
如果设置此参数,一个IteratorStatus的实例将会压入每一个遍历的堆栈 |
value |
否 |
|
Object/String |
要遍历的可枚举的(iteratable)数据源,或者将放入的新列表(List)的对想 |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
I18n(国际化操作)
描述:
加载资源包到值堆栈。它可以允许text标志访问任何资源包的信息。而不只当前的action相关联的资源包。
名称 |
必需 |
默认 |
类型 |
描述 |
name |
是 |
|
Object/String |
资源包的类路径(如com.xxxx.resources.AppMsg) |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
Include
描述:包含一个servlet的输出(servlet或jsp的页面)
名称 |
必需 |
默认 |
类型 |
描述 |
value |
时 |
|
String |
要包含的jsp页面或servlet |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
param
描述:属性是可选的,如果提供,会调用Component的方法,addParameter(String,Object),如果不提供,则外层嵌套标签必须实现UnnamedParametric接口。
Value的提供有两种方式,通过value属性或者标签中间的text,不同之处:
参数会以String的格式放入statck
该值会以java.lang.Object的格式放入statck
名称 |
必需 |
默认 |
类型 |
描述 |
name |
否 |
|
String |
参数名 |
value |
时 |
|
String |
value表达式 |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
set
描述:set标签赋予变量一个特定范围内的值。当希望给一个变量赋一个复杂的表达式,每次访问该变量而不是复杂的表达式时用到。其在两种情况下非常有用:复杂的表达式很耗时(性能提升)或者很难理解(代码的可读性提高)
参数:
名称 |
必需 |
默认 |
类型 |
描述 |
name |
是 |
|
String |
变量名字 |
scope |
否 |
|
String |
变量作用域,可以为application,session,request,page,action |
value |
否 |
|
Object/String |
将会赋给变量的值 |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
Text
描述:支持国际化信息的标签。国际化信息必须放在一个和当前action同名的resource bundle中,如果没有找到相应message,tagbody将被当作默认的message,如果没有tag body,message的name会被作为默认message.
名称 |
必需 |
默认 |
类型 |
描述 |
name |
是 |
|
String |
资源属性的名字 |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
url
描述:该标签用于创建url,可以通过”param”标签提供request参数。
当includeParams的值是all或get,param标签中定义的参数将有优先权,也就是说其会覆盖其他同名参数的值。
UI标志
单行文本框
Textfield标签输出一个HTML单行文本输入控件,等价于HTML代码
名称 |
必需 |
默认 |
类型 |
描述 |
maxlength |
否 |
无 |
Integer |
文本输入控件可以输入字符的最大长度 |
readonly |
否 |
false |
Boolean |
当该属性为true时,不能输入 |
size |
否 |
无 |
Integer |
指定可视尺寸 |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
例子:
文本框区
Textarea标签输出一个HTML多行文本输入控件,等价于HTML代码:
名称 |
必需 |
默认 |
类型 |
描述 |
cols |
否 |
无 |
Integer |
列数 |
rows |
否 |
无 |
Integer |
行数 |
readonly |
否 |
false |
Boolean |
当该属性为true时,不能输入 |
wrap |
否 |
false |
Boolean |
指定多行文本输入控件是否应该换行 |
id |
否 |
|
Object/String |
用来标识元素的id。在ui和表单中为HTML的id属性 |
例子:
<s:textareaname="personal"cols="10" rows="5" label="个人简历">s:textarea>
下拉列表
s:select标签输出一个下拉列表框,相当于HTML代码中的
名称 |
必需 |
默认 |
类型 |
描述 |
list |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容 |
listKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value |
listValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容 |
headerKey |
否 |
无 |
String |
设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值 |
headerValue |
否 |
无 |
String |
显示在页面中header选项内容 |
emptyOption |
否 |
false |
Boolean |
是否在header选项后面添加一个空选项 |
multiple |
否 |
false |
Boolean |
是否多选 |
size |
否 |
无 |
Integer |
显示的选项个数 |
例子:
%@ page contentType="text/html;charset=GBK" %>
<%@ taglib prefix="s"uri="/struts-tags" %>
<h3>使用name和list属性,list属性的值是一个列表h3>
<s:form>
<s:select label="最高学历" name="education" list="{'高中','大学','硕士','博士'}"/>
s:form>
<h3>使用name和list属性,list属性的值是一个Maph3>
<s:form>
<s:select label="最高学历" name="education" list="#{1:'高中',2:'大学',3:'硕士',4:'博士'}"/>
s:form>
<h3>使用headerKey和headerValue属性设置header选项h3>
<s:form>
<s:select label="最高学历" name="education" list="{'高中','大学','硕士','博士'}"
headerKey="-1" headerValue="请选择您的学历"/>
s:form>
<h3>使用emptyOption属性在header选项后添加一个空的选项h3>
<s:form>
<s:select label="最高学历" name="education" list="{'高中','大学','硕士','博士'}"
headerKey="-1" headerValue="请选择您的学历"
emptyOption="true"/>
s:form>
<h3>使用multiple属性设置多选h3>
<s:form>
<s:select label="最高学历" name="education" list="{'高中','大学','硕士','博士'}"
headerKey="-1" headerValue="请选择您的学历"
emptyOption="true"
multiple="true"/>
s:form>
<h3>使用size属性设置下拉框可显示的选项个数h3>
<s:form>
<s:select label="最高学历" name="education" list="{'高中','大学','硕士','博士'}"
headerKey="-1" headerValue="请选择您的学历"
emptyOption="true"
multiple="true" size="8"/>
s:form>
<h3>使用listKey和listValue属性,利用Action实例的属性(property)来设置选项的值和选项的内容h3>
<s:form>
<s:select label="最高学历" name="education" list="educations"
listKey="id" listValue="name"/>
s:form
doubleselect标签
doubleselect标签输出关联的两个HTML列表框,产生联动效果。
名称 |
必需 |
默认 |
类型 |
描述 |
list |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容 |
listKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value,该选项只对第一个列表框起作用 |
listValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容,该选项只对第一个列表框起作用 |
headerKey |
否 |
无 |
String |
设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值 |
headerValue |
否 |
无 |
String |
显示在页面中header选项内容 |
emptyOption |
否 |
false |
Boolean |
|
multiple |
否 |
false |
Boolean |
是否多选 |
size |
否 |
无 |
Integer |
显示的选项个数,该选项只对第一个列表框起作用 |
doubleId |
否 |
无 |
String |
指定第二个列表框的ID |
doubleList |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合 |
doubleListKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value,该选项只对第二个列表框起作用 |
doubleListValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容,该选项只对第二个列表框起作用 |
doubleSize |
否 |
无 |
Integer |
选项个数 |
doubleName |
否 |
无 |
String |
指定第二个列表框的name映射 |
doubleValue |
否 |
无 |
Object |
第二个列表框的初始选种项 |
实例:
<s:form name="test">
<s:doubleselect label="请选择所在省市"
name="province" list="{'四川省','山东省'}" doubleName="city"
doubleList="top == '四川省' ? {'成都市', '绵阳市'} : {'济南市', '青岛市'}" />
s:form>
<s:form action="doubleselectTag">
<s:doubleselect
label="请选择所在省市"
name="province"
list="provinces"
listKey="id"
listValue="name"
doubleList="cities"
doubleListKey="id"
doubleListValue="name"
doubleName="city"
headerKey="-1"
headerValue="---------- 请选择 ----------"
emptyOption="true" />
s:form>
复选框
名称 |
必需 |
默认 |
类型 |
描述 |
fieldValue |
是 |
true |
String |
指定在复选框选中时,实际提交的值 |
复选框组,对应Action中的集合
名称 |
必需 |
默认 |
类型 |
描述 |
list |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容 |
listKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value |
listValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容 |
例子:checkboxlistTag.jsp
<%@ page contentType="text/html;charset=GBK" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:form>
<s:checkboxlist name="interest"list="{'足球','篮球','排球','游泳'}" label="兴趣爱好"/>
s:form>
单击复选框
文件选择组建
file标签输出一个HTML文件选择框。
名称 |
必需 |
默认 |
类型 |
描述 |
accept |
否 |
input |
String |
HTML accept属性,指出接受文件的MIME类型 |
按钮
Submit标签输出一个按钮,submit标签和form标签使用可以提供异步表单提交功能。Submit标签可以输出以下三种类型的提交按钮:
Input:等价于 HTML代码
Image:等价于 HTML代码<input type="image">
Button:<button type="submit">button>
名称 |
必需 |
默认 |
类型 |
描述 |
type |
否 |
input |
String |
要使用的提交按钮的类型,有效值:input button image |
src |
否 |
无 |
String |
为image类型的提交按钮设置图片地址。该属性对input和button类型的提交按钮无效 |
action |
否 |
无 |
String |
指定处理提交请求的action |
method |
否 |
无 |
String |
指定处理提交请求的action的方法 |
实例
实例1.<s:submit type="image" method="login" src="images/login.jpg">s:submit>
页面输出:
type="image" alt="Submit" src="images/login.jpg" id="user__login" name="method:login" value="Submit"/>
实例2.<s:submit type="button" action="selectTag" method="login" label="登陆">s:submit>
页面输出:
>
Struts2预定义的前缀:
1。method method:login
使用method前缀,来取代action默认的execute()方法的执行。
<s:form action="user">
<s:textfield name="user.username"label="用户名">s:textfield>
<s:textfield name="user.password"label="密码">s:textfield>
<s:submit value="登陆" name="method:login">s:submit>
<s:submit value="注册" name="method:register">s:submit>
s:form>
注意:1。input类型的按钮,不能用label设置按钮上的文本,只能用value
2、action前缀
使用action前缀,取代form标签指定的action,导向到另一个action进行处理。
<s:form action="login">
<s:textfield name="user.username"label="用户名">s:textfield>
<s:textfield name="user.password"label="密码">s:textfield>
<s:submit value="登陆">s:submit>
<s:submit value="注册" name="action:register">s:submit>
s:form>
2、redirect前缀
使用redirect前缀请求重定向到其他的url,甚至可以是web英语程序外部的url。
<s:form action="login">
<s:textfield name="user.username"label="用户名">s:textfield>
<s:textfield name="user.password"label="密码">s:textfield>
<s:submit value="登陆">s:submit>
<s:submit value="搜索" name="redirect:www.google.com">s:submit>
s:form>
2、redirect-action前缀
使用redirect-action前缀请求重定向到其他的action.
<s:form action="login">
<s:textfield name="user.username"label="用户名">s:textfield>
<s:textfield name="user.password"label="密码">s:textfield>
<s:submit value="登陆">s:submit>
<s:submit value="搜索" name="redirect-action:register">s:submit>
s:form>
reset标签
reset标签输出一个重置按钮
名称 |
必需 |
默认 |
类型 |
描述 |
type |
否 |
input |
String |
要使用的重置按钮的内容,input、button |
<s:reset value="重置">s:reset>
<s:reset type="button" label="重置">s:reset>
updownselect标签
updownselect标签创建一个带有上下移动的按钮的列表框,可以通过上下移动按钮来调整列表框的选项的位置。
名称 |
必需 |
默认 |
类型 |
描述 |
list |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容 |
listKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value |
listValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容 |
headerKey |
否 |
无 |
String |
设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值 |
headerValue |
否 |
无 |
String |
显示在页面中header选项内容 |
emptyOption |
否 |
false |
Boolean |
是否在header选项后面添加一个空选项 |
multiple |
否 |
false |
Boolean |
是否多选 |
size |
否 |
无 |
Integer |
显示的选项个数 |
moveUplabel |
否 |
|
String |
设置向上移动按钮上的文本 |
moveDownLabel |
否 |
|
String |
设置向下移动按钮上的文本 |
selectAllLabel |
否 |
|
String |
设置向全部选择按钮上的文本 |
allowMoveUp |
否 |
无 |
Boolean |
设置是否使用向上移动按钮 |
allowMoveDown |
否 |
无 |
Boolean |
设置是否使用向下移动按钮 |
allowSelectAll |
否 |
无 |
Boolean |
设置是否使用全部选择按钮 |
实例:
<s:form>
<s:updownselect name="a" label="请选择您喜欢的图书" labelposition="top"
moveUpLabel="向上移动"
list="{'Spring2.0宝典' , '轻量级J2EE企业应用实战' , 'JavaScript: The Definitive Guide'}"/>
<s:updownselect name="b" label="请选择您想选择出版日期" labelposition="top"
moveDownLabel="向下移动"
list="#{'Spring2.0宝典':'2006年10月' , '轻量级J2EE企业应用实战':'2007月4月' , '基于J2EE的Ajax宝典':'2007年6月'}"
listKey="key"
emptyOption="true"
listValue="value"/>
<s:bean name="com.zhaosoft.ui.formtag.BookService"id="bs"/>
<s:updownselect name="c" label="请选择您喜欢的图书的作者" labelposition="top"
selectAllLabel="全部选择" multiple="true"
list="#bs.books"
listKey="author"
listValue="name"/>
s:form>
package com.zhaosoft.ui.formtag;
publicclass BookService
{
public Book[] getBooks()
{
returnnew Book[]
{
newBook("Spring2.0宝典","zhaosoft"),
newBook("轻量级J2EE企业应用实战","zhaosoft"),
newBook("基于J2EE的Ajax宝典","zhaosoft")
};
}
}
optiontransferselect标签
optiontransferselect标签创建一个选项转移列表组建,它由两个标签以及它们之间的用于将选项在两个之间相互移动的按钮组成。表单提交时,将提交两个列表框中选中的选项。
名称 |
必需 |
默认 |
类型 |
描述 |
list |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合,使用集合中的元素来设置各个选项,如果list的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容,该选项只对第一个列表框起作用 |
listKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value,该选项只对第一个列表框起作用 |
listValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容,该选项只对第一个列表框起作用 |
headerKey |
否 |
无 |
String |
设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值 |
headerValue |
否 |
无 |
String |
显示在页面中header选项内容 |
multiple |
否 |
false |
Boolean |
是否多选 |
size |
否 |
无 |
Integer |
显示的选项个数,该选项只对第一个列表框起作用 |
doubleId |
否 |
无 |
String |
指定第二个列表框的ID |
doubleList |
是 |
无 |
Cellection Map Enumeration Iterator array |
要迭代的集合,使用集合中的元素来设置各个选项,如果doubleList的属性为Map则Map的key成为选项的value,Map的value会成为选项的内容,该选项只对第二个列表框起作用 |
doubleListKey |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的value,该选项只对第二个列表框起作用 |
doubleListValue |
否 |
无 |
String |
指定集合对象中的哪个属性作为选项的内容,该选项只对第二个列表框起作用 |
doubleHeaderKey |
否 |
无 |
String |
设置当用户选择了header选项时,提交的的value,如果使用该属性,不能为该属性设置空值 |
doubleHeaderVale |
否 |
无 |
String |
显示在页面中header选项内容 |
doubleEmptyOption |
否 |
无 |
String |
是否在第二列表框的header后面添加一个空选项 |
doubleMultiple |
否 |
true |
Boolean |
是否多选 |
doubleSize |
否 |
无 |
Integer |
选项个数 |
doubleName |
否 |
无 |
String |
指定第二个列表框的name映射 |
doubleValue |
否 |
无 |
Object |
第二个列表框的初始选种项 |
leftTitle |
否 |
无 |
String |
左边列表框的标题 |
rightTitle |
否 |
<- |
String |
右边列表框的标题 |
addToLeftLable |
否 |
|
String |
|
addToRightLable |
|
|
|
|
addAllToLeftLable |
|
|
|
|
addAllToRightLable |
|
|
|
|
leftUpLabel |
|
|
|
|
leftDownLabel |
|
|
|
|
rightUpLabel |
|
|
|
|
rightDownLabel |
|
|
|
|
allowAddToLeft |
|
|
|
|
allowAddToright |
|
|
|
|
allowAddAllToLeft |
|
|
|
|
allowAddAllToRight |
|
|
|
|
allowSelectAll |
否 |
无 |
Boolean |
设置是否使用全部选择按钮 |
allowUpdownOnLeft |
|
|
|
|
allowUpDownOnRight |
|
|
|
|
例子:
<s:head/>
<s:form>
<s:optiontransferselect
label="最喜爱的图书"
name="javaBook"
list="{'《Java Web开发详解》', '《Struts 2深入详解》', '《Java快速入门》'}"
doubleName="cBook"
doubleList="{'《VC++深入详解》', '《C++ Primer》', '《C++程序设计语言》'}"/>
s:form>
---------------------------
<s:form>
<s:optiontransferselect
label="最喜爱的图书"
name="book1"
leftTitle="Java图书"
rightTitle="C/C++图书"
list="{'《Java Web开发详解》', '《Struts 2深入详解》', '《Java快速入门》'}"
headerKey="-1"
headerValue="--- 请选择 ---"
emptyOption="true"
doubleName="book2"
doubleList="{'《VC++深入详解》', '《C++ Primer》', '《C++程序设计语言》'}"
doubleHeaderKey="-1"
doubleHeaderValue="--- 请选择 ---"
doubleEmptyOption="true"
addToLeftLabel="向左移动"
addToRightLabel="向右移动"
addAllToLeftLabel="全部左移"
addAllToRightLabel="全部右移"
selectAllLabel="全部选择"
leftUpLabel="向上移动"
leftDownLabel="向下移动"
rightUpLabel="向上移动"
rightDownLabel="向下移动"/>
s:form>
Struts2中的OGNL
本人是一个EL(Expression Language,以下译为表达式语言)的支持者。因为我对<% %>写法极为反感,忘记了在那本书上看到的一句话——“使用标志(Tag)的一个目的就是避免在JSP页面中出现过多的<%%>的语句,使页面与后台代码分离。”
表达式语言主要有以下几大好处:
Struts 2支持以下几种表达式语言:
Struts 2默认的表达式语言是OGNL,原因是它相对其它表达式语言具有下面几大优势:
OGNL是通常要结合Struts2的标志一起使用,如
首先新建名为Struts2_OGNL的Web工程,配置开发环境。之前很多朋友在使用Struts 2的过程中都遇到乱码问题。当然乱码问题由来已久,而且涉及多方面的知识,所以并非三言两语可以说明白,而且互联网上也已经有很多这方便的文章,大家可以Google一下。不过,如果你在开发的过程,多注意一下,避免乱码问题也不难。乱码多数是由于编码与解码所使用的方式不同造成的,所以我建议大家将编码方式都设为“utf-8”,如<%@ page language="java"contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>。另外,在配置web.xml时使用ActionContextCleanUp过滤器(Filter),如下面代码所示:
xml version="1.0"encoding="UTF-8"?>
<web-app id="WebApp_9"version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Struts 2 OGNLdisplay-name>
<filter>
<filter-name>struts-cleanupfilter-name>
<filter-class>
org.apache.struts2.dispatcher.ActionContextCleanUp
filter-class>
filter>
<filter-mapping>
<filter-name>struts-cleanupfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>struts2filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
filter-class>
filter>
<filter-mapping>
<filter-name>struts2filter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<welcome-file-list>
<welcome-file>index.htmlwelcome-file>
welcome-file-list>
web-app>
清单1 WebContent/WEB-INF/web.xml
“#”主要有三种用途:
名称 |
作用 |
例子 |
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属性,直到找到为止 |
下面让我们它们的具体写法,首先是Action类代码:
package tutorial.action;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.util.ServletContextAware;
import tutorial.model.Book;
import com.opensymphony.xwork2.ActionSupport;
publicclass OgnlAction extends ActionSupport implements ServletRequestAware, SessionAware, ServletContextAware {
privatestaticfinallong serialVersionUID = 1L;
private HttpServletRequest request;
private Map
private List
this.request = request;
}
@SuppressWarnings("unchecked")
publicvoid setSession(Map session) {
this.session = session;
}
publicvoid setServletContext(ServletContext application) {
this.application = application;
}
public List
return books;
}
@Override
public String execute() {
request.setAttribute("userName", "Max From request");
session.put("userName", "Max From session");
application.setAttribute("userName", "Max Fromapplication");
books = new LinkedList
books.add(
books.add(new Book("978-0596007867","The Art of Project Management", 35.96));
books.add(new Book("978-0201633610","Design Patterns: Elements of Reusable Object-Oriented Software",43.19));
books.add(new Book("978-0596527341","Information Architecture for the World Wide Web: Designing Large-ScaleWeb Sites", 25.19));
books.add(new Book("978-0735605350","Software Estimation: Demystifying the Black Art", 25.19));
return SUCCESS;
}
}
清单2 src/tutorial/action/OgnlAction.java
以上代码分别在request、session和application的范围内添加“userName”属性,然后再在JSP页面使用OGNL将其取回。我还创建了Book对象的列表用于演示“用于过滤和投影(projecting)集合”的功能,至于Book的代码大家可以在我前一文章《在Struts 2中实现CRUD》看到。
下面是Ognl.jsp的代码,内容如下:
<%@page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8" %>
<%@taglib prefix="s" uri="/struts-tags" %>
DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts OGNL Demotitle>
head>
<body>
<h3>访问OGNL上下文和Action上下文h3>
<p>parameters: <s:property value="#parameters.userName"/>p>
<p>request.userName: <s:property value="#request.userName"/>p>
<p>session.userName: <s:property value="#session.userName"/>p>
<p>application.userName: <s:property value="#application.userName"/>p>
<p>attr.userName: <s:property value="#attr.userName"/>p>
<hr />
<h3>用于过滤和投影(projecting)集合h3>
<p>Books more than $35p>
<ul>
<s:iteratorvalue="books.{?#this.price> 35}">
<li><s:propertyvalue="title"/> - $<s:property value="price"/>li>
s:iterator>
ul>
<p>The price of "Code Complete, SecondEdition" is: <s:propertyvalue="books.{?#this.title=='CodeComplete, Second Edition'}.{price}[0]"/>p>
<hr />
<h3>构造Maph3>
<s:set name="foobar" value="#{'foo1':'bar1','foo2':'bar2'}"/>
<p>The value of key "foo1" is <s:property value="#foobar['foo1']"/>p>
body>
html>
清单3 WebContent/Ognl.jsp
以上代码值得注意的是“
最后是Struts 2的配置文件struts.xml,内容如下:
xml version="1.0"encoding="UTF-8"?>
DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true"/>
<package name="Struts2_OGNL_DEMO" extends="struts-default">
<actionname="Ognl" class="tutorial.action.OgnlAction">
<result>/Ognl.jspresult>
action>
package>
struts>
清单4 src/struts.xml
发布运行应用程序,结果如下所示:
清单5 示例运行结果1
“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:
<hr />
<h3>%的用途h3>
<p><s:url value="#foobar['foo1']"/>p>
<p><s:url value="%{#foobar['foo1']}"/>p>
清单6 演示%用途的代码片段
刷新页面,结果如下所示:
清单7 示例运行结果2
“$”有两个主要的用途
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack"/>
<result type="redirect">ListPhotos.action?albumId=${albumId}result>
action>
清单8 演示$用途的代码片段
OGNL是一种功能很大的表达式语言,熟悉它可以使我们的开发变得更快捷。