借助 Ajax 自动保存 JSF 表单之一

在客户端获取表单数据

本节将给出一个 JSF 表单,其数据通过 JavaScript 和 DOM 在 Web 浏览器中获得。 您可以在自已的 Web 表单应用程序中重用这里介绍的 JavaScript 代码。本节还将解释如何正确地编码表单数据以将它提交给服务器。

构建 JSF 表单

让我们先来看一个典型的 JSF 例子。SupportForm.jsp 这个页面包括一些基本 HTML 的元素,比如输入框、列表、单选按钮、复选框和提交按钮。所有输入组件都将其值绑定到称为 SupportBean 的 JavaBean 属性。这个页面的头部包括一个 <script> 标记,用来导入 AutoSaveScript.js 文件。此 JavaScript 文件包括一个函数,名为 setAutoSaving(),它在 <body> 标记的 onload 属性内调用,以便在 Web 浏览器加载页面后激活表单的自动保存功能。接下来显示了 SupportForm.jsp 页的部分源代码。

包含示例 JSF 表单的 SupportForm.jsp 页

<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

<html>
<head>
<title>Support Form</title>
<script src="AutoSaveScript.js">
</script>
</head>
<body οnlοad="setAutoSaving(10000)">

<f:view>

<h1>Support Form</h1>

<h:form id="supportForm">

<p><h:outputText value="Name: "/>
<h:message for="name"/><br>
<h:inputText id="name" value="#{supportBean.name}"
size="40" required="true">
</h:inputText>
...
<p><h:outputText value="Platform: "/>
<h:message for="platform"/><br>
<h:selectOneRadio id="platform" value="#{supportBean.platform}"
layout="lineDirection" required="true">
<f:selectItem itemValue="Windows" itemLabel="Windows"/>
<f:selectItem itemValue="Linux" itemLabel="Linux"/>
<f:selectItem itemValue="Mac" itemLabel="Mac"/>
</h:selectOneRadio>
...
<p><h:outputText value="Problem: "/>
<h:message for="problem"/><br>
<h:inputTextarea id="problem" value="#{supportBean.problem}"
rows="10" cols="40" required="true"/>

<p><h:commandButton id="submit" value="Submit"
action="#{supportBean.submit}"/>

</h:form>

</f:view>

</body>
</html>

当用户为了打开 JSF 页面而单击一个 JSF 链接或输入一个 URL 时,Web 浏览器会构建 HTTP 请求并把此请求发送至 Web 服务器,服务器识别包含页面的应用程序并会调用 FacesServlet(在 web.xml 内配置)来处理此请求。在进行了某些上下文初始化后,就会执行此页面,而且,JSF 框架还会创建组件树以镜像该 Web 页面所用的 JSF 标记。这些组件的呈现程序生成含有表单元素的 HTML 代码。

SupportForm.jsp 页面生成的 HTML 代码

<html>
<head>
<title>Support Form</title>
<script src="AutoSaveScript.js">
</script>
</head>
<body οnlοad="setAutoSaving(10000)">

<h1>Support Form</h1>

<form id="supportForm" method="post"
action="/autosave/faces/SupportForm.jsp"
enctype="application/x-www-form-urlencoded">

<p>Name: <br>
<input id="supportForm:name" type="text"
name="supportForm:name" size="40" />
...
<p>Platform: <br>
<table id="supportForm:platform">
<tr>
<td><label><input type="radio" name="supportForm:platform"
value="Windows"> Windows</input></label></td>
<td><label><input type="radio" name="supportForm:platform"
value="Linux"> Linux</input></label></td>
<td><label><input type="radio" name="supportForm:platform"
value="Mac"> Mac</input></label></td>
</tr>
</table>
...
<p>Problem: <br>
<textarea id="supportForm:problem" name="supportForm:problem"
cols="40" rows="10">
</textarea>

<p><input id="supportForm:submit" type="submit"
name="supportForm:submit" value="Submit" />

<input type="hidden" name="com.sun.faces.VIEW"
value="H4sIAA..." />
<input type="hidden" name="supportForm" value="supportForm" />

</form>

</body>
</html>

在这个 HTML 表单的结尾,有一些隐藏元素。如果 javax.faces.STATE_SAVING_METHOD 参数在web.xml 文件中被设为 client,那么 JSF 实现会内部使用这些隐藏元素以识别所提交的表单和存储组件树在请求间的状态。从浏览器的角度看,一个 JSF 表单与其他 HTML 表单无异,可以使用 JavaScript 和DOM 在 Web 浏览器中访问表单元素。

获取及编码表单数据

AutoSaveScript.js 文件包含一个称为 getFormData() 的 JavaScript 函数,它获取一个 form 对象并对其元素进行迭代以构建包含名称-值对的字符串。这个字符串遵循标准的 application/x-www-form-urlencoded 格式,用 & 分隔参数,并在每个参数的名称和值之间使用 =。内部函数 addParam() 可以对单一参数进行编码,所使用的是 JavaScript API 提供的 escape() 函数。escape() 函数用 % 后跟被编码字符的两位 16 进制码代替了几乎所有非字母数字的 ASCII 字符。 我之所以说 “几乎所有非字母数字的 ASCII 字符”,是因为除此之外,还有字母数字字符以及无编码的其他一些字符(例如 +)。

例如,如果将字符串 a + b 传递给 escape(),结果将是 a%20+%20b(20 是空格符的 16 进制码)。这是一个符合 RFC 1738 的有效 URL 编码,但如果将这个已编码的字符串提交给服务器端脚本,例如JSP,结果将是一个空格而不是 + 字符。这也是正确的,因为描述 application/x-www-form-urlencoded 格式的RFC 1866 中规定空格符的编码为 +,并且所有非字母数字字符都以一个 % 后跟 16 进制码替代。当服务器对这个字符串进行解码时,任何 + 字符都会被还原成一个空格。

总之,由 escape() 执行的 URL 编码并不完全与 application/x-www-form-urlencoded 一样,因为 escape() 将 + 字符保留,不做编码,而在 application/x-www-form-urlencoded 中,空格则被编码为 + 字符。解决这个问题最简单的方法是将所有 + 字符都编码为 %2B(2B 是 + 的 16 进制代码)。也可以使用replace() 对 escape() 的返回结果执行此操作。在本例中,可以将字符串 a + b 编码为 a%20%2B%20b。下列所示的是 addParam() 内部函数,它将一个编码后的名称-值对添加到 getFormData() 的本地dataString 变量。

对单一请求参数进行编码

function getFormData(form) {
var dataString = "";

function addParam(name, value) {
dataString += (dataString.length > 0 ? "&" : "")
+ escape(name).replace(/\+/g, "%2B") + "="
+ escape(value ? value : "").replace(/\+/g, "%2B");
}
...
}

getFormData() 函数获取 form 对象的 elements 数组,并根据每个元素的类型调用 addParam()。单个名称-值会针对每个文本框、密码和隐藏字段添加。只有当对应的表单元素被选中时,复选框和单选按钮的值才会被编码。如果是列表,单个名称-值对会针对每个选中项添加。之后,getFormData() 会返回包含表单编码数据的字符串。

function getFormData(form) {
...
var elemArray = form.elements;
for (var i = 0; i < elemArray.length; i++) {
var element = elemArray[i];
var elemType = element.type.toUpperCase();
var elemName = element.name;
if (elemName) {
if (elemType == "TEXT"
|| elemType == "TEXTAREA"
|| elemType == "PASSWORD"
|| elemType == "HIDDEN")
addParam(elemName, element.value);
else if (elemType == "CHECKBOX" && element.checked)
addParam(elemName,
element.value ? element.value : "On");
else if (elemType == "RADIO" && element.checked)
addParam(elemName, element.value);
else if (elemType.indexOf("SELECT") != -1)
for (var j = 0; j < element.options.length; j++) {
var option = element.options[j];
if (option.selected)
addParam(elemName,
option.value ? option.value : option.text);
}
}
}
return dataString;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值