Struts2的Ajax标签介绍
常用的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>远程Div</title>
<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("----------");
%>
服务器返回的随机数字是:<s:property value="rdmStr"/>
第二个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>远程Div</title>
<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>远程Div</title>
<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 1</div>
<br/>
<div id="t2" style="background-color:#bbbbbb;width:360px;height:80px">Div 2</div>
<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">接执行远程JavaScript</s: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"/>
<!-- targets属性设置用于装载被改变的HTML元素 -->
<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<String> books = new ArrayList<String>();
public String getAuthor()
{
return author;
}
public void setAuthor(String author)
{
this.author = author;
}
public List<String> getBooks()
{
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" %>
[
<s:iterator value="books">
["<s:property/>"],
</s:iterator>
]
转发至微博