18.4  AjaxTags常用标签的使用

AjaxTags提供的标签并不是特别多,但这些标签都是特别常用的,例如自动完成、级联菜单等。使用AjaxTags的标签才能真正让我们从烦琐的JavaScript处理中抽身而出,以“非常Java”的方式优雅地完成Ajax应用。

18.4.1  使用自动完成标签

自动完成标签的功能类似于Internet Explorer中文本框具有的功能,系统可以根据用户的输入提示自动完成选择。

假设输入城市,如果用户输入“广”,系统会读取数据库,对比数据库的记录,找出所有以“广”开头的城市,例如“广岛”和“广州”,从而提供给用户选择。这种自动完成的Ajax应用在第11章已经介绍过了,但那个自动完成应用大约有200多行的JavaScript代码,下面以AjaxTags来完成这个Ajax应用。自动完成功能使用ajax:autocomplete,这个标签有如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

baseUrl:这是一个必需属性,该属性定义了Ajax请求发送的URL。该属性指定的URL将返回一个典型的AjaxTags所需要的XML响应,响应的每个item节点的name值就是自动完成的提供给用户选择的一项。该属性支持表达式语言。

source:这是一个必需属性,该属性指定的HTML元素的值一旦发生改变,就将发送Ajax请求。通常,该属性的文本将作为自动完成的前缀部分,即source元素指定的HTML元素里的文本将被作为请求参数,伴随着Ajax请求一同发送,一旦该请求参数发送到服务器的baseUrl,baseUrl处的服务器响应将返回一个满足条件的XML响应。当然,也可以指定其他请求参数。

target:这是一个必需属性,该属性指定一个文本框,该文本框将显示自动完成的选择项对应的value。如果用户无须使用额外的文本框来显示value,则可将该参数设置为与source相同。

parameters:这是一个必需属性,该属性指定了Ajax请求的请求参数。

className:这是一个必需属性,该属性指定了自动完成所提供的下拉框的CSS样式单的名字。通常,系统提供该CSS样式单,但用户也可以自定义自己的 CSS样式单。

indicator:这是一个可选属性,该属性指定一个HTML元素,该元素在Ajax请求开始时出现,随着Ajax交互完成而隐藏。该元素可以通知用户Ajax交互的进度。

minimumCharacters:这是一个可选属性,该属性指定自动完成最少所需的字符数。假设source指定一个文本框,如果minimumCharacters的属性值为2,则至少要求source指定的文本框提供两个字符的输入,系统才会提供自动完成功能。

appendSeparator:这是一个可选属性,一旦设置了该属性,target属性指定的文本框的值就不会被覆盖,而是在后面添加上自动完成的value节点的值,添加时将以appendSeparator属性指定的字符串作为分隔符。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

parser:这是一个可选属性,该属性指定一个服务器响应的解析器,通常无须指定该解析器,除非用户需要自己完成特别的工作。默认的解析器是ResponseHtmlParser。

为了更好地演示Ajax应用,首先引入了一个JavaBean,这个JavaBean表示一本书,书里包含书名和出版社两个属性。下面是Book类的代码:

//普通的值对象(VO)

public class Book implements Serializable

{

//Book类包含的两个属性

private String name;

private String publisher;

//Book类的构造器

public Book()

{

}

//Book类的构造器,构造时传入两个参数

public Book(String name, String publisher) {

this.name = name;

this.publisher = publisher;

}

//name属性的setter方法

public void setName(String name) {

this.name = name;

}

//publisher属性的setter方法

public void setPublisher(String publisher) {

this.publisher = publisher;

}

//name属性的getter方法

public String getName() {

return (this.name);

}

//publisher属性的getter方法

public String getPublisher() {

return (this.publisher);

}

/**

* 重写的toString方法

* @see java.lang.Object#toString()

*/

public String toString()

{

return new ToStringBuilder(this).append("书名:", name).append("出

版社:", publisher).toString();

}

}

该Book类就是一个普通的值对象(VO),它包装了在页面中显示的Java实例。

为了简单起见,我们不再使用复杂的持久层组件,即不再使用数据库来保存数据,不使用DAO组件来完成数据库访问,而是将所有的数据以静态属性的方式保存在业务逻辑组件中,业务逻辑组件不再需要依赖持久层组件,而是直接访问静态属性,从而提供业务逻辑的实现。考虑到后面的AjaxTags标签,此处的BookService组件包含了多个业务逻辑方法。

下面是BookService类的源代码:

public class BookService

{

//以此静态属性代替数据库保存的数据

static final List<Book> books = new ArrayList<Book>();

//添加数据

static

{

//添加电子工业出版社出版的书籍

books.add(new Book("Spring2.0宝典", "电子工业出版社"));

books.add(new Book("Java入门与精通", "电子工业出版社"));

books.add(new Book("Spring实战", "电子工业出版社"));

books.add(new Book("Hibernate入门与精通", "电子工业出版社"));

books.add(new Book("Java网络编程", "电子工业出版社"));

//添加清华大学出版社出版的书籍

books.add(new Book("软件工程导论", "清华大学出版社"));

books.add(new Book("Java教程", "清华大学出版社"));

books.add(new Book("Hibernate持久化", "清华大学出版社"));

books.add(new Book("Java动画设计", "清华大学出版社"));

//添加机械工业出版社出版的书籍

books.add(new Book("软件工程的艺术", "机械工业出版社"));

books.add(new Book("Java高级程序设计", "机械工业出版社"));

books.add(new Book("Spring项目指南", "机械工业出版社"));

books.add(new Book("Java项目指南", "机械工业出版社"));

}

//构造器

public BookService()

{

}

/**

* 根据出版社查询所出版的书

* @param publisher 出版社

* @return 该出版社所出的全部书籍

*/

public List getBooksByPublisher(String publisher)

{

//作为结果返回的集合对象

List<Book> result = new ArrayList<Book>();

//遍历所有的书,从中选出publisher出版社的书

for ( Book book : books)

{

if (book.getPublisher().equalsIgnoreCase(publisher))

{

result.add(book);

}

}

return result;

}

/**

* 根据书名前缀返回以该前缀开始的全部书籍

* @param prefix 书名前缀

* @return 所有以prefix开头的书籍

*/

public List<Book> getBooksByPrefix(String prefix)

{

//作为结果返回的集合对象

List<Book> result = new ArrayList<Book>();

//遍历所有的书,从中选出所有以prefix开头的书籍

for (Book book : books)

{

if (book.getName().toLowerCase().startsWith(prefix.toLowerCase()))

{

result.add(book);

}

}

return result;

}

/**

* 返回全部书籍

* @return 所有书籍

*/

public List<Book> getAllBooks()

{

return books;

}

}

这个BookService业务逻辑组件将作为本节所有示例程序的业务逻辑组件。本示例程序在添加书籍实例时,并未考虑书籍的真实性,只是随便添加,作为应用示例使用,请读者不要误会。本业务逻辑组件将所有的持久层数据作为组件属性保存,并未真正从数据库读取。下面是自动完成的Servlet,该Servlet基于BaseAjaxServlet完成,其代码如下:

//自动完成的Servlet,继承BaseAjaxServlet

public class AutocompleteServlet extends BaseAjaxServlet

{

//重写getXmlContent方法,该方法的返回值作为Ajax请求的响应

public String getXmlContent(HttpServletRequest request, HttpServletResponse

response) throws Exception

{

//获得请求参数

String prefix = request.getParameter("prefix");

System.out.println("xxx" prefix);

//创建业务逻辑组件的实例

BookService service = new BookService();

//返回以特定前缀开始的所有书籍

List list = service.getBooksByPrefix(prefix);

//借助于AjaxXmlBuilder返回XML字符串

AjaxXmlBuilder builder = new AjaxXmlBuilder();

try

{

builder = builder.addItems(list, "name", "publisher");

return builder.toString();

}

catch (Throwable e)

{

e.printStackTrace();

}

return null;

}

}

该Servlet根据发送的请求参数调用业务逻辑组件方法,从所有的书籍中选择出所有书名以prefix开头的书籍。将该Servlet配置在web.xml文件中,该Servlet即能对Ajax请求提供响应。在web.xml文件中增加如下片段来完成Servlet的配置:

<!-- 配置Servlet -->

<servlet>

<!-- Servlet的名字  -->

<servlet-name>autocomplete</servlet-name>

<!-- Servlet的实现类  -->

<servlet-class>lee.AutocompleteServlet</servlet-class>

</servlet>

<!-- 配置Servlet的映射 -->

<servlet-mapping>

<!-- Servlet的名字  -->

<servlet-name>autocomplete</servlet-name>

<!-- Servlet映射的URL  -->

<url-pattern>/autocomplete</url-pattern>

</servlet-mapping>

一旦完成了该Servlet的映射,即可在页面中使用autocomplete标签,该标签提供了自动完成功能。下面是在页面中使用自动完成标签的代码片段:

<ajax:autocomplete

//根据书名文本框的值改变来发送Ajax请求

source="name"

//将value节点的值输入publisher文本框

target="publisher"

//Ajax请求的发送地址

baseUrl="autocomplete"

//自动完成的提示框的CSS样式单

className="autocomplete"

//请求参数,其中{name}是表达式,输出name表单域的值

parameters="prefix={name}"

//当Ajax交互时显示indicator

indicator="indicator"

//至少需要两个字符才发送Ajax请求

minimumCharacters="2"

/>

图18.3显示了自动完成的示范效果。

图18.3  自动完成示范

一旦用户选择了相应的书籍,该书籍的出版社将自动填写在publisher文本框内。

18.4.2  使用area标签

该标签允许在页面中开辟出一个单独区域,而该区域的超链接请求等不会刷新整个页面,而是仅刷新部分内容。该标签有如下几个属性。

id:这是一个必需属性,该属性指定area的ID,用于唯一标识该area,该属性值将成为area对应的DIV元素的ID属性值。

ajaxFlag:这是一个可选属性,该属性指定该页面的其他部分是否忽略Ajax请求。

style:这是一个可选属性, 用于指定内联的CSS样式。

styleClass:这是一个可选属性,用于指定CSS样式单名。

ajaxAnchors:这是一个可选属性。

下面是一个使用area标签的示例代码片段:

<!-- 定义一个页面范围内的Java实例 -->

<jsp:useBean id="now" class="java.util.Date"/>

<!-- 使用表达式输出页面内的Java实例 -->

日期:${now}<p>

<!-- 使用ajaxl:area标签 -->

<ajax:area id="myarea" style="background:#eeeeee; width:300px; height:80px;"

ajaxAnchors="true" ajaxFlag="myarea">

简单的页面area

<br/>

<a href="pagearea.jsp">单击此处</a>

<br/>

<!-- 使用表达式输出页面内的Java实例 -->

日期: ${now}

</ajax:area>

页面中分别有两次输出当前时间的代码,有两次输出now变量的代码。因为后一个日期的输出放在ajax:area标签内,单击“单击此处”超链接时,页面刷新,但不会刷新整个页面,仅刷新ajax:area标签内的部分内容。如果单击了“单击此处”超链接,那么可看到第二个日期发生了改变,但第一个日期不会被刷新。图18.4显示了ajax:area的局部刷新效果。

图18.4  ajax:area的局部刷新

18.4.3  使用anchors标签

这是一个超链接标签,但该超链接标签与普通的超链接不同,该超链接标签仅刷新页面的局部——刷新ajax:area标签指定的页面部分。因此,该标签必须与ajax:area一起使用。该标签有如下两个属性。

target:这是一个必需属性,该属性指定刷新的ajax:area元素的ID属性。

ajaxFlag:这是一个可选属性,该属性指定页面的其他部分是否忽略Ajax请求。

使用ajax:anchors标签,可以通过页面中的超链接而不是ajax:area中的超链接来控制局部刷新。

<jsp:useBean id="now" class="java.util.Date"/>

日期:${now}<p>

<ajax:anchors target="myarea" ajaxFlag="myarea"><a href="anchors.jsp">

单击此处</a></ajax:anchors>

<ajax:area id="myarea" style="background:#eeeeee; width:300px; height:80px;"

ajaxAnchors="true" ajaxFlag="myarea">

简单的页面area

<br/>

<a href="anchors.jsp">单击此处</a>

<br/>

日期: ${now}

</ajax:area>

在上面的页面中有两个超链接,一个是页面范围的超链接,一个是在ajax:area范围内的超链接。两个超链接都可以控制页面的局部刷新。

18.4.4  使用callout标签

该标签是一个服务器提示功能,这个功能以前通常在客户端完成,当用户的鼠标移动到某个产品上面时,该产品上将出现一个提示框,但这个提示框的信息往往是写在客户端的。通过使用callout标签,可以让服务器响应作为提示框的信息。从AjaxTags 1.2以后,该功能的实现依赖于OverLIBMWS JavaScript库,因此应将其JavaScript库复制到对应的Web应用中。该标签支持如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

baseUrl:这是一个必需属性,该属性定义了Ajax请求发送的URL。该属性指定的URL将返回一个典型的AjaxTags所需要的XML响应,响应的每个item节点的name值就是自动完成功能提供给用户选择的一项。该属性支持表达式语言。

source:该属性指定哪个HTML元素将触发服务器提示框,即指定哪个HTML元素触发Ajax请求。必须指定source和sourceClass两个属性之一。

sourceClass:该属性指定一类HTML元素将触发服务器提示框,即指定哪些HTML元素是该CSS样式单,这些HTML元素都可以触发Ajax请求。必须指定source和sourceClass两个属性之一。

parameters:伴随Ajax请求发送的请求参数。该属性的值支持一个特殊的变量ajaxParameter,该变量代表发送请求的内容。

title:这是一个可选属性,该属性指定信息提示框的标题。

overlib:这是一个可选属性,该属性指定OverLib库的各种选项。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

callout标签所需要的XML响应只需要一个item节点,该节点的name节点值将作为提示的标题显示,而value节点值将作为提示的内容显示。下面是示例应用的Servlet:

//作为AjaxTags响应的Servlet

public class CalloutServlet extends BaseAjaxServlet

{

//重写getXmlContent方法

public String getXmlContent(HttpServletRequest request, HttpServletResponse

response) throws Exception

{

//Ajax请求总以utf-8编码集发送

request.setCharacterEncoding("UTF-8");

//获取请求参数

String param = request.getParameter("book");

System.out.println(param);

//第一个参数是name节点的值,作为提示的标题

//第二个参数是value节点的值,作为提示的内容

AjaxXmlBuilder builder = new AjaxXmlBuilder().addItemAsCData(

"提示标题",

"<p>关于书籍:<b>" param "</b>的信息如下:<br>"

"服务器的提示信息 </p>");

return builder.toString();

}

}

将该Servlet配置在应用中,为了配置该Servlet,在web.xml文件中增加如下片段:

<!-- 配置Servlet -->

<servlet>

<!-- Servlet的名字  -->

<servlet-name>callout</servlet-name>

<!-- Servlet的实现类  -->

<servlet-class>lee. CalloutServlet</servlet-class>

</servlet>

<!-- 配置Servlet的映射 -->

<servlet-mapping>

<!-- Servlet的名字  -->

<servlet-name> callout </servlet-name>

<!-- Servlet映射的URL  -->

<url-pattern>/ callout </url-pattern>

</servlet-mapping>

该Servlet即可响应用户的Ajax请求,下面是页面中使用callout标签的代码片段:

<div style="font-size: 90%; width: 650px; border: 1px dashed #999; padding: 10px">

<p>

下面是目前J2EE领域内容最丰富的三本书:<p>

<!-- 下面3个HTML元素的class属性为book -->

<li><a href="javascript:void(0)" class="book">Spring2.0宝典</a>

<li><a href="javascript:void(0)" class="book">轻量级J2EE企业开发实战</a>

<li><a href="javascript:void(0)" class="book">Ajax开发宝典</a>

</p>

</div>

<!-- 使用callout标签  -->

<ajax:callout

//Ajax请求发送的URL

baseUrl="callout"

//所有class属性为book的HTML元素都将触发Ajax请求

sourceClass="book"

//请求参数

parameters="book={ajaxParameter}"

title="书籍详细信息"

/>

读者应该看到parameters属性的值为book={ajaxParameter},其中,ajaxParameter是一个特殊的变量,这个变量代表任何发送请求的HTML元素本身。当“Spring2.0宝典”发送请求时,该变量的值就是“Spring2.0宝典”。图18.5显示了这种服务器提示的效果。

图18.5  服务器提示

18.4.5  使用htmlContent标签

该标签能将一个HTML页面的内容显示在当前页面的某个区域内(通常是一个DIV元素)。该标签不再需要XML响应,它只需要一个标准的HTML响应,这个HTML响应将直接输出页面的目标容器。该标签有如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

baseUrl:这是一个必需属性,该属性指定了Ajax请求发送的URL。

source:该属性指定哪个HTML元素将触发服务器提示框,即指定哪个HTML元素触发Ajax请求。必须指定source和sourceClass两个属性之一。

sourceClass:该属性指定一类HTML元素将触发服务器提示框,即指定哪些HTML元素是该CSS样式单,这些HTML元素都可以触发Ajax请求。必须指定source和sourceClass两个属性之一。

target:这是一个必需属性,该属性指定了HTML响应的输出容器。

parameters:这是一个可选属性,如果需要发送请求参数,则需要使用该属性。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

下面是提供了htmlContent响应的Servlet,该Servlet不再生成XML响应,而是生成HTML响应。

public class HtmlContentServlet extends BaseAjaxServlet

{

//重写getXmlContent方法,生成服务器响应

public String getXmlContent(HttpServletRequest request, HttpServletResponse

response) throws Exception

{

//设置服务器解码方式

request.setCharacterEncoding("UTF-8");

//获取请求参数

String publisher = request.getParameter("publisher");

//创建业务逻辑组件实例

BookService service = new BookService();

//根据出版社获取所有的书籍

List<Book> list = service.getBooksByPublisher(publisher);

//开始拼接返回的字符串

StringBuffer html = new StringBuffer();

html.append("<h3>").append(publisher).append("出版的书籍包括如下</h3>");

for (Book book: list)

{

html.append("<li>").append(book.getName()).append("</li>");

}

html.append("</ul>");

html.append("<br>");

html.append("最后更新时间:" new Date());

return html.toString();

}

}

正如在代码中看到的,该Servlet不再借助于AjaxXmlBuilder类来辅助生成XML响应,该Servlet不再返回一个XML文件,而是返回一个HTML文档。htmlContent会将该响应直接输出在HTML文档的目标元素中。将该Servlet配置在Web应用中,在web.xml文件中增加如下片段:

<servlet>

<servlet-name>htmlContent</servlet-name>

<servlet-class>lee.HtmlContentServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>htmlContent</servlet-name>

<url-pattern>/htmlContent</url-pattern>

</servlet-mapping>

在页面中使用ajax:htmlContent标签,本页面中使用了两种方式来输出htmlContent内容,一种是采用超链接,一种是采用下拉框。代码片段如下:

选择出版社查看详细信息:<br>

<ul>

<!-- 下面使用超链接来生成htmlContent -->

<li><a href="javascript://nop/" class="publisher">电子工业出版社</a></li>

<li><a href="javascript://nop/" class="publisher">清华大学出版社</a></li>

<li><a href="javascript://nop/" class="publisher">机械工业出版社</a></li>

</ul>

<!-- 下面使用下拉列表来生成htmlContent -->

<p>选择出版社查看详细信息:</p>

<select id="publishSelector" name="publishSelector">

<option value="电子工业出版社">电子工业出版社</option>

<option value="清华大学出版社">清华大学出版社</option>

<option value="机械工业出版社">机械工业出版社</option>

</select>

<>

<div id="bookDesc" style="position:absolute;left:300px;top:20px;background-color:

#ffffaa"> </div>

<!--  第一次使用htmlContent标签 -->

<ajax:htmlContent

baseUrl="htmlContent"

//所有class属性为publisher的HTML元素都将发送Ajax请求

sourceClass="publisher"

//指定输出HTML响应的目标容器

target="bookDesc"

parameters="publisher={ajaxParameter}"

/>

<!--  第二次使用htmlContent标签 -->

<ajax:htmlContent

baseUrl="htmlContent"

//指定publisherSelector元素发送Ajax请求

source="publishSelector"

//指定输出HTML响应的目标容器

target="bookDesc"

//发送请求参数

parameters="publisher={publishSelector}"

/>

页面中的超链接和下拉框都可以激发HTML内容,一旦用户单击了超链接或者选择了下拉列表,都可以看到该出版社出版的所有图书。图18.6显示了htmlContent标签的效果。

图18.6  使用htmlContent输出HTML响应

18.4.6  使用portlet标签

portlet标签将在页面上生成一个Portlet区域,该区域的内容直接显示服务器端HTML响应。类似于htmlContent标签,该标签不需要 XML响应,而是支持HTML响应。使用ajax:portlet标签还可以定义该Portlet的内容是否支持周期性刷新。该标签包含如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

baseUrl:这是一个必需属性,该属性指定了Ajax请求发送的URL。

source:这是一个必需属性,该属性指定了Portlet的ID属性值。

parameters:这是一个可选属性,该属性指定发送Ajax请求的请求参数。

classNamePrefix:这是一个可选属性,该属性指定了Portlet的Box,Tools,refresh,Size,Close,Title和Content元素的CSS样式单。

title:这是一个必需属性,该属性指定Portlet的标题。

imageClose:这是一个可选属性,该属性指定关闭按钮的图标。

imageMaximize:这是一个可选属性,该属性指定最大化按钮的图标。

imageMinimize:这是一个可选属性,该属性指定最小化按钮的图标。

imageRefresh:这是一个可选属性,该属性指定刷新按钮的图标。

refreshPeriod:这是一个可选属性,该属性指定Portlet的内容刷新频率,即隔多少秒刷新一次。如果没有指定该属性,则Portlet的内容不会自动刷新,除非手动刷新。默认情况下,当页面加载时,Portlet的内容也会刷新,但如果设置executeOnLoad 为false,则页面载入时,Portlet的内容不会刷新,除非手动刷新。

executeOnLoad:这是一个可选属性,该属性指定当页面重载时,是否重新检索Portlet里的内容,默认是重新检索。

expireDays:这是一个可选属性,该属性指定cookie持久保存的天数。

expireHours:这是一个可选属性,该属性指定cookie持久保存的小时数。

expireMinutes:这是一个可选属性,该属性指定cookie持久保存的分钟数。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

该标签需要的响应完全类似于htmlContent标签的响应,此处不再单独为该标签编写服务器处理类,而是直接向htmlContent发送Ajax请求,因此可以在页面中直接使用portlet标签。使用portlet标签的代码片段如下:

<ajax:portlet

//指定Portlet的ID 属性

source="tsinghua"

//发送请求的URL

baseUrl='htmlContent'

//Portlet必需的CSS样式

classNamePrefix="portlet"

//Portlet的标题

title="清华大学出版社 Portlet"

//指定几个按钮的图标

imageClose="img/close.png"

imageMaximize="img/maximize.png"

imageMinimize="img/minimize.png"

imageRefresh="img/refresh.png"

//请求参数

parameters="publisher=清华大学出版社"

//每5s刷新一次该Portlet

refreshPeriod="5" />

<ajax:portlet

source="phei"

baseUrl='htmlContent'

classNamePrefix="portlet"

title="电子工业出版社 Portlet"

imageClose="img/close.png"

imageMaximize="img/maximize.png"

imageMinimize="img/minimize.png"

imageRefresh="img/refresh.png"

parameters="publisher=电子工业出版社"

refreshPeriod="5" />

上面的页面使用了两个Portlet,页面执行的效果如图18.7所示,其中清华大学出版社的Portlet已经被最小化了,因此看不到该Portlet的内容。

图18.7  使用portlet标签生成Portlet效果

18.4.7  使用select标签

select标签就是在18.2和18.3节中频繁使用的标签,它的主要作用是实现级联下拉框效果。所谓级联下拉框,就是根据第一个下拉框选择的值,动态改变第二个下拉框的选项。select标签有如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

baseUrl:这是一个必需属性,该属性指定了Ajax请求发送的URL。

source:这是一个必需属性,该属性指定了第一个下拉框的ID属性,当该属性指定的下拉框改变时触发Ajax交互。

target:这是一个必需属性,该属性指定了第二个下拉框的ID属性,当Ajax响应完成后,AjaxTags会根据响应来自动更新该属性指定的下拉框。

parameters:这是一个可选属性,如果需要发送请求参数,则需要使用该属性。

eventType:这是一个可选属性,该属性指定了源对象上触发请求的事件类型。

executeOnLoad:这是一个可选属性。

defaultOptions:这是一个可选属性,该属性是一系列以逗号隔开的值,这些值将总是作为第二个下拉框的默认选项。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

parser:这是一个可选属性,该属性指定一个服务器响应的解析器。通常无须指定该解析器,除非用户需要自己完成特别的工作。默认的解析器是ResponseHtmlParser。

因为在18.2和18.3节中已经大量使用了该标签,因此此处不再给出关于它的示范应用。值得注意的是,select标签只能有一个源下拉框和一个目标下拉框,这往往不能满足实际需要。

例如,对于一个常用场景:第一个下拉框是国家,第二个下拉框是省份,第三个下拉框是城市。每个下拉框的值都应该随前面下拉框值的改变而改变。AjaxTags的select也可以满足这个需要,只要使用两个select标签即可。

对于第一个select标签,国家下拉框是源下拉框,省份下拉框是目标下拉框;对于第二个select标签,省份下拉框是源下拉框,城市下拉框是目标下拉框。

使用select标签可以很方便地实现多级联动下拉框。

18.4.8  创建Tab页

Tab页的创建依赖于两个标签:tabPanel和tab。tabPanel是一个整体的Tab效果,而每个tab则是该Tab效果里的每个tab页。因此,tabPanel和tab两个标签通常一起使用。tabPanel标签包含如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

panelStyleId:这是一个必需属性,指定Tab页的ID属性值。

contentStyleId:这是一个必需属性,指定Tab页面内容的ID属性值。

panelStyleClass:这是一个可选属性,该属性指定Tab页整体使用的CSS样式单。

contentStyleClass:这是一个可选属性,该属性指定Tab页内容所使用的CSS样式单。

currentStyleClass:这是一个必需属性,该属性指定了激活的Tab页所使用的CSS样式单。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction :这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

parser:这是一个可选属性,该属性指定一个服务器响应的解析器。通常无须指定该解析器,除非用户需要自己完成特别的工作。默认的解析器是ResponseHtmlParser。

tab标签包含如下几个属性。

baseUrl:这是一个必需属性,该属性指定了Ajax请求发送的URL。

caption:这是一个必需属性,该属性指定了Tab页的标题。

defaultTab:这是一个可选属性,该属性指定页面是否作为Tab效果的初始页。

parameters:这是一个可选属性,如果加载页面时需要发送请求参数,则需要使用该属性。

值得注意的是,tab标签的Ajax响应无须使用XML响应,而应该使用标准的HTML响应,tab标签将该HTML内容直接输出在Tab页中。

下面的应用示范一个简单的Tab效果,每个Tab页面的baseUrl都使用前面htmlContent中已经定义了的htmlContent Servlet。下面是使用tabPanel和tab标签的代码片段:

<!-- 使用tabPanel构建整体的Tab效果  -->

<ajax:tabPanel

panelStyleId="tabPanel"

contentStyleId="tabContent"

panelStyleClass="tabPanel"

contentStyleClass="tabContent"

currentStyleClass="ajaxCurrentTab">

<!-- tabPanel的每个tab子标签对应一个Tab页 -->

<ajax:tab caption="电子工业出版社"

baseUrl="htmlContent"

parameters="publisher=电子工业出版社"

defaultTab="true"/>

<ajax:tab caption="清华大学出版社"

baseUrl="htmlContent"

parameters="publisher=清华大学出版社"/>

<ajax:tab caption="机械工业出版社"

baseUrl="htmlContent"

parameters="publisher=机械工业出版社"/>

</ajax:tabPanel>

上面的代码将ajax:tab标签放在ajax:tabPanel内,从而形成一个整体的Tab效果,每个tab标签对应一个基本的Tab页,每个Tab页所显示的URL完全相同,请求参数不同,每个Tab页的内容也不相同。图18.8显示了该Tab效果。

图18.8  Tab效果

18.4.9  使用displayTag标签

这个标签需要依赖于Apache组织下的DisplayTag项目,AjaxTags封装了DisplayTag项目,但增加了Ajax引擎,以便能以Ajax的方式来排序、分页。该标签的核心是DisplayTags项目,读者应该具有DisplayTags的相关知识。AjaxTags中的displayTag标签有如下几个属性。

id:这是一个必需属性,该属性指定了displayTag对应的DIV元素的ID属性值。

ajaxFlag:这是一个可选属性,该属性指定该页面的其他部分是否忽略Ajax请求。

style:内联CSS样式单属性。

styleClass:这是一个可选属性,该属性指定displayTag的CSS样式单属性。

pagelinksClass:这是一个可选属性,该属性指定DisplayTag的分页导航栏的CSS样式。

tableClass:这是一个可选属性,该属性指定DisplayTag的table元素的CSS样式。

columnClass:这是一个可选属性,该属性指定DisplayTag里table中每列的CSS样式。

baseUrl:这是一个可选属性,没有太大的作用。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

为了使用AjaxTags的displayTag标签,必须先在Web应用中安装DisplayTags项目。安装DisplayTags可以按如下步骤进行:

       将displaytag-{version}.jar文件复制到Web应用的WEB-INF/lib下。

       将DisplayTag所依赖的JAR文件复制到Web应用的WEB-INF/lib下。这个步骤对于AjaxTags而言,往往已经完成了,因此无须额外复制。

       如果使用JSP 1.1或者更早的容器,则应该将displaytag-{taglibversion}.tld文件复制到Web应用的WEB-INF/路径下,并在web.xml文件中配置标签库。配置标签库的代码如下:

<taglib>

<!-- 标签库所在的URI ->

<taglib-uri>http://displaytag.sf.net</taglib-uri>

<!-- 指定标签库TLD文件所在的物理路径 -->

taglib-location>/WEB-INF/displaytag-{taglibversion}.tld</taglib-location>

</taglib>

       如果需要使用Display的导出选项(这种导出选项非常有用,它可以将表格显示的内容直接导出成XML文档和Excel文档等),则应该在web.xml文件中配置如下:

<filter>

<filter-name>ResponseOverrideFilter</filter-name>

<filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>ResponseOverrideFilter</filter-name>

<url-pattern>/displaytag.jsp</url-pattern>

</filter-mapping>

       如果需要自定义DisplayTag显示的某些效果,则还需要增加一个displaytag.properties文件,关于该文件的各种属性以及具体含义可以参考DisplayTag的官方文档。下面是本示例应用增加在WEB-INF/classes路径下的displaytag.properties文件:

sort.behavior=list

sort.amount=list

basic.empty.showtable=true

basic.msg.empty_list=找不到满足要求的结果

paging.banner.placement=bottom

paging.banner.some_items_found=查询到{0}条记录, 当前显示从{2}到{3}条记录.

export.types=csv excel xml

export.amount=list

export.csv=false

export.excel=true

export.pdf=true

export.xml=false

export.excel.include_header=true

因为该文件中包含了中文字符,因此还必须使用native2ascii命令将该属性文件转为国际化的属性文件。经过这5个步骤,该Web应用就可以使用AjaxTags的displayTag标签了。在页面中使用displayTag标签的代码如下:

<jsp:useBean id="now" class="java.util.Date"/>

<!-- 直接初始化业务逻辑组件 -->

<jsp:useBean id="service" class="lee.BookService" />

<!-- 将display标签放在ajax:displayTag标签内,以便可以以Ajax方式进行排序、分页 -->

<ajax:displayTag id="displayTagFrame" ajaxFlag="displayAjax">

最后更新时间: ${now}

<display:table name="service.allBooks" class="displaytag" pagesize="10"

scope="page"defaultsort="1" defaultorder="descending" export="true"

id="row" excludedParams="ajax">

<!-- 输出业务逻辑组件中的两列 -->

<display:column property="name" title="书名" sortable="true" headerClass=

"sortable" />

<display:column property="publisher" title="出版社" sortable="true" headerClass=

"sortable" />

</display:table>

</ajax:displayTag>

在浏览器中浏览该页面,将看到如图18.9所示的效果。

图18.9  使用AjaxTags的displayTag标签

可以看到,页面中两次输出的时间并不相同,那是因为这里已经单击了“书名”列,从而按书名排序了,只是这种排序是以Ajax方式进行的,因此只刷新表格部分,并未刷新整个页面内容,从而看到两个时间并不相同。

如果单击表格下面的分页导航,则可看到以Ajax方式完成分页。如果单击下面的导出Excel按钮,将可以看到如图18.10所示的界面,这是DisplayTag的功能,与Ajax的displayTag并没有什么关系。

图18.10  导出Excel文档的效果

18.4.10  使用updateField标签

这个标签实现了一种常用的效果:当一个表单域的输入完成后,其他几个表单域的值根据该表单域的值计算得到。在大部分时候,如果这种计算无须服务器数据参与,则可以在客户端通过JavaScript计算完成。在某些情况下,例如,商品的折扣是通过后台程序设定的,则需要服务器数据的参与,因此应该使用该标签来完成。updateFiled标签有如下几个属性。

var:这是一个可选属性,该属性定义了autocomplete标签创建的JavaScript对象名。通常无须指定该属性。

attachTo:这是一个可选属性,该属性定义了var对应的自动完成对象将应用到的对象。

baseUrl:这是一个必需属性,该属性指定了Ajax请求发送的URL。

source:这是一个必需属性,该属性指定一个表单域,该表单域的值将作为请求参数随Ajax请求向服务器发送。

target:这是一个必需属性,该属性的值以逗号隔开,指定了一系列的表单域,Ajax响应的结果将在这些表单域中输出。

action:这是一个必需属性,该属性指定的HTML元素能触发onclick事件,该事件将触发Ajax交互。

parameters:这是一个可选属性,该属性指定需要发送到服务器端的请求参数。

eventType:这是一个可选属性,该属性指定能触发Ajax请求的事件类型。

preFunction:这是一个可选属性,该属性指定了Ajax交互之前自动执行的函数。

postFunction:这是一个可选属性,该属性指定了Ajax交互完成后自动执行的函数。

errorFunction:这是一个可选属性,该属性指定服务器响应出错时执行的函数。

parser:这是一个可选属性,该属性指定一个服务器响应的解析器,默认采用ResponseHtmlParser解析器;如果使用XML响应,则通常指定为ResponseXmlParser。

值得注意的是,该标签的响应一样是一个标准的AjaxTags响应,该响应包含的item节点数应与需要动态计算的表单域的数量相等,而且每个item节点的name节点值应与目标表单域的ID属性相同。

下面的应用示范了通过一个初始价格计算出五星级会员、四星级会员、三星级会员、二星级会员和一星级会员的会员价。计算打折价的Servlet的代码如下:

public class CalDiscountServlet extends BaseAjaxServlet

{

//重写getXmlContent方法,该方法返回的XML字符串作为Ajax请求的响应

public String getXmlContent(HttpServletRequest request, HttpServletResponse

response)

{

//price为初始价

double price = 0;

//下面5个变量分别为不同级别会员的打折价

double five = 0;

double four = 0;

double three = 0;

double two = 0;

double one = 0;

//获取请求参数

price = Double.parseDouble(request.getParameter("price"));

//调用服务器计算

five = price * 0.7;

four = price * 0.8;

three = price * 0.85;

two = price * 0.9;

one = price * 0.95;

//构造响应的XML字符串,并返回

return new AjaxXmlBuilder()

.addItem("five", Double.toString(five))

.addItem("four", Double.toString(four))

.addItem("three", Double.toString(three))

.addItem("two", Double.toString(two))

.addItem("one", Double.toString(one))

.toString();

}

}

上面代码中的addItem有两个参数:第一个参数分别为five和four等,这些参数并不是随意填写的,应与页面中需要通过服务器计算的表单域的ID属性相同,即页面中的five表单域的值等于Double.toString(five)。

页面中使用updateField标签来完成该Ajax交互,因为同时有5个表单域需要通过计算得到,因此target的值为以逗号隔开的5个值。下面是页面中使用updateField的代码片段:

<ajax:updateField

baseUrl="calDiscount"

//发送自动计算的源表单域

source="price"

//下面5个表单域将通过计算得到

target="five,four,three,two,one"

//action元素触发Ajax请求

action="action"

//发送的请求参数

parameters="price={price}"

parser="new ResponseXmlParser()"/>

在页面中的初始价格文本框中输入“80”,然后单击“计算”按钮,将出现如图18.11所示的界面。

图18.11  服务器计算表单域的值

18.5  关于AjaxTags的选择

正如前面介绍的,通过使用AjaxTags标签完成一个Ajax应用是如此简单,对于常见的Ajax应用场景,AjaxTags都提供了对应的封装,程序开发者只需要使用JSP标签即可开发出功能完备的Ajax应用。但AjaxTags并不是万能的,有些时候,我们必须放弃AjaxTags,选择更烦琐的开发方式。

18.5.1  AjaxTags的优势和使用场景

AjaxTags的优势相当明显,当Ajax技术面世时,有这样一种说法:Ajax通过对程序员的折磨来取悦用户。这种说法在某种程度上是对的,但所有的技术都以改善用户感受为最终目标,对于一个程序员而言,能带给用户更好的体验就是最大的成就。

Ajax技术的烦琐不言而喻,JavaScript本身不是一门严格的语言,缺乏严格的调试机制,即使在底层所有响应完成后,程序员还必须在表现层完成异常烦琐的DOM更新,还必须应用CSS样式。如果再加上跨浏览器支持、向后兼容性等一系列的技巧,那么开发一个普通的Ajax页面可能需要两天时间,这简直不可想象。

多亏了大量的JavaScript库,例如Prototype.js和Dojo等,但即使使用这些JavaScript库,我们依然需要面对很多问题,依然需要动态更新DOM,依然必须编写大量的JavaScript代码。

实际上,大量的Ajax应用场景重复出现,级联下拉框、自动完成、页面提示……每个常用的Ajax交互都需要花费大量的时间和精力。

AjaxTags对这些常用的Ajax交互场景提供了封装,程序开发者几乎无须编写任何JavaScript代码就可以完成一个专业的Ajax应用。特别是对于J2EE应用开发者而言,编写一个传统的Servlet,并将该Servlet配置在Web应用中,然后在页面中使用Ajax标签即可完成一个Ajax应用,相当简单。

AjaxTags最大的优点是简单,J2EE应用开发者甚至无须了解Ajax技术细节,只需要会编写Servlet,会使用JSP标签,就可以开发出专家级的Ajax应用,这是AjaxTags提供的最大好处。

因为AjaxTags简单,所以也可以大大节省开发者的时间。

对于所有能使用AjaxTags的情况,推荐优先考虑使用AjaxTags,因为使用AjaxTags既可以节省时间,也可以避免错误。AjaxTags的更新非常快,经常有新的标签加入,每个beta版之间的标签数量、标签的用法也存在差异,希望读者在使用AjaxTags时到其官方站点看一看AjaxTags的最新版包含了那些简便的标签。

18.5.2  AjaxTags的缺点

AjaxTags以简单、快捷的特性方便了J2EE的Ajax开发者,但它也不是万能的,在某些情形下,它依然存在一些小小的缺陷。AjaxTags大致存在如下缺陷:

AjaxTags只能在J2EE应用环境下使用,不能在其他Web编程脚本语言(如ASP和PHP等)中使用。

AjaxTags的高度封装虽然简化了Ajax的开发,但导致灵活性严重丧失;对于复杂的Ajax交互,使用AjaxTags完成更加烦琐。

AjaxTags对Ajax交互提供了封装,但不像Dojo那样提供了一个调试环境。整个Ajax交互不仅对普通浏览者透明,对于应用开发者也是透明的,调试难度相对较大。

虽然存在这些缺点,但AjaxTags的简单远远可以掩盖这些缺陷,在能使用AjaxTags标签的地方,应该尽量考虑使用AjaxTags。如果需要对AjaxTags进行大量扩展、修改,则应该考虑使用其他技术。毕竟,AjaxTags与其他Ajax技术并不是互斥的,例如Prototype.js本身就是AjaxTags所依赖的技术;如果有必要,还可以引入Dojo

基于J2EE的Ajax宝典------ AjaxTags相关推荐

  1. 基于J2EE架构的项目开发团队中的角色与职责

    [声明] 1.2内容来源:<J2EE Architects Handbook>中文翻译<J2EE系统架构师参考手册>[翻译 Mellon] 1.角色 Technical arc ...

  2. 基于jquery的ajax聊天室系统,基于jQuery的Ajax聊天室应用毕业设计(含外文翻译)...

    基于jQuery的Ajax聊天室应用毕业设计(含外文翻译) 毕业设计(论文) I 基于基于 jQuery 的的 Ajax 聊天室应用聊天室应用 摘摘 要要 随着网络的逐渐普及,以及网络技术的不断发展, ...

  3. ajax无刷新留言板远吗,基于jquery实现ajax无刷新评论

    基于jquery实现ajax无刷新评论 发布于 2017-03-31 11:26:07 | 75 次阅读 | 评论: 0 | 来源: 网友投递 jQuery javascript框架jQuery是一个 ...

  4. 基于J2EE+JBPM3.x/JBPM4.3+Flex流程设计器+Jquery+授权认证)企业普及版贝斯OA与工作流系统...

    基于J2EE+JBPM3.x/JBPM4.3+Flex流程设计器+Jquery+授权认证)企业普及版贝斯OA与工作流系统 课程学习地址:http://***/goods.php?id=173 本项目是 ...

  5. Java毕设项目-商城管理系统-基于J2EE/SSM化妆品商城系统的设计与实现

    题目:商城管理系统-基于J2EE/SSM化妆品商城系统的设计与实现 重点作为毕设项目 1.开发环境 语言:Java       Spring+Springmvc+Mybatis[简称SSM] 数据库: ...

  6. java语言在scada系统中的应用_基于J2EE平台的SCADA系统实现

    1前言数据采集与监控SCADA系统除了实现对远方设备进行控制.对系统的运行参数进行监测的基本功能外,同时还承担着向能量管理系统(energymanagementsystem,EMS)及其它相关自动化系 ...

  7. 应用 Rational 工具简化基于 J2EE 的项目第 8 部分 :测试软件

    本文是演示了在分布式的.基于 J2EE 的项目中使用 Rational 工具的系列文章(如下面所列)的第 8 部分. 第 1 部分: 项目介绍:高层次计划 第 2 部分: 风险管理:需求管理 第 3 ...

  8. 计算机应用与jaj,基于J2EE银鸽集团ERP系统的设计与应用-计算机应用技术专业论文.docx...

    基于J2EE银鸽集团ERP系统的设计与应用-计算机应用技术专业论文 郑州大学硕士学位论文 郑州大学硕士学位论文基于J2EE银鸽集团ERP系统的设计与应用 摘要 银钨集团是河南省造纸行业中的龙头企业之一 ...

  9. 基于J2EE架构的在线考试系统-Java(报告+源码+PPT

    目前国内基于B/S.C/S结构的在线考试系统产品已经有许多,本文首先介绍了这些考试系统的形成和发展过程,大致结构.然后通过仔细分析,提出了目前的这些系统还存有系统更新和维护等种种弊端,仍不够成熟.基于 ...

最新文章

  1. tomcat的jdbc连接池PoolExhaustedException
  2. Sqlserver UrlEncode
  3. 云时代,运维要么自己写代码,要么开发替你写了
  4. COOKIESESSION 入门
  5. ubuntu 把软件源修改为国内源和更新(转载)
  6. 10件产品3件次品,7件正品,不放回的取,第三次取得次品的概率-----三种解法
  7. paip.mysql 批量kill 连接.
  8. 华为鸿蒙可用型号,华为鸿蒙系统支持手机型号一览
  9. git format-patch命令介绍
  10. 项目分享之敲击床头盒控制床头灯的开关
  11. 用matlab求二重积分例题_数学建模matlab例题参考及练习
  12. Matlab中绘制颜色渐变曲线
  13. IDEA创建mybatis的xml文件
  14. 沧小海读《图解TCP/IP》笔记——第六章 TCP与UDP
  15. 工业互联网和物联网有什么关系?
  16. 古墓里出土的那些奇怪文物,能否证明穿越的存在?
  17. 关系数据理论必备知识点
  18. BT种子制作教程 轻松培育网络种子
  19. openfalcon-hbs-learn
  20. 如何黑掉一台根本不联网的电脑?

热门文章

  1. MTK 平台手势唤醒功能
  2. 工业通信网络的架构、应用场景及需求
  3. Android APK签名原理及方法
  4. Elon为2020网鼎杯准备之“CTF初体验!”
  5. JavaFX中Image的路径问题
  6. 基于Docker的拓扑网络搭建可行性探究
  7. 感悟:思想总结也要勤快,思想的懒惰更危险
  8. linux 网卡自动挂死,shell脚本自动检测网络掉线和自动重连
  9. mha检测mysql状况方式_MHA搭建
  10. http://localhost/打开错误原因之一,eclipse PHP Web Application没反应 解决方法