1. 概述
Jersey 是一个使用 Java 开发 Web 服务和客户端的全面开源框架。通过 Jersey,我们可以创建支持完整 HTTP 功能的强大 Web 应用程序。
本文将探讨 Jersey 中的两个特定功能:@FormDataParam
和 @FormParam
注解。尽管这两个注解在本质上相似,但它们之间存在显著差异,如下所述。
2. 背景
客户端与服务器之间交换数据的方式有很多种,XML 和 JSON 是其中最受欢迎的,但并非唯一选择。当客户端是网页时,另一种数据格式是表单编码数据。这是因为 HTML 使得定义包含各种输入(文本、复选框、下拉列表等)的表单变得简单,并将这些数据发送到远程服务器。
这就是 @FormDataParam
和 @FormParam
注解的作用之处。它们都在 Jersey 服务器应用程序中用于处理表单数据,但有一些重要的区别。
现在我们了解了这两个注解的背景,接下来我们将看看如何使用它们以及它们的一些差异。
3. 使用 @FormParam
简而言之,当 API 预期 URL 编码数据时,我们会使用 @FormParam
注解。让我们看一个只有文本字段的简单 HTML 表单:
<form method="post" action="/example1">
<input name="first_name" type="text">
<input name="last_name" type="text">
<input name="age" type="text">
<input type="submit">
</form>
这个表单有三个字段:名字、姓氏和年龄。它使用 HTTP POST 方法将表单数据发送到 /example1 的 URL。
要在 Jersey 中处理此表单,我们在服务器应用中定义以下端点:
@POST
@Path("/example1")
public String example1(
@FormParam("first_name") String firstName,
@FormParam("last_name") String lastName,
@FormParam("age") String age)
{
// process form data
}
请注意,我们在 HTML 表单的每个字段上都使用了注解。无论表单有多少或何种类型的字段,这都是一样的。通过使用 @FormParam
注解,Jersey 将表单值绑定到相应的方法参数。
实际上,表单编码数据对应于 MIME 类型 application/x-www-form-urlencoded
。在浏览器和我们的服务之间发送的数据背后,看起来像这样:
first_name=john&last_name=smith&age=42
这种做法的好处在于数据处理起来相对容易,因为它只涉及文本,没有二进制数据。此外,由于字符串可以作为查询参数在 URL 中传递,这种方法也可以使用 HTTP GET 方法。然而,通过 URL 传递表单数据时应谨慎,因为可能包含敏感信息。
4. 使用 @FormDataParam
相比之下,@FormDataParam
注解更为灵活,可以处理任何组合的文本和二进制数据。在实践中,这对于通过 HTML 表单上传文件非常有用。
让我们看一个使用 @FormDataParam
注解的例子。首先,我们需要将 jersey-media-multipart
模块从 Maven 中心仓库 导入到项目中:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>3.1.3</version>
</dependency>
现在,让我们在上面创建的 HTML 表单中添加一个文件上传字段:
<form method="post" action="/example2" enctype="multipart/form-data >
<input name="first_name" type="text">
<input name="last_name" type="text">
<input name="age" type="text">
<input name="photo" type="file">
<input type="submit">
</form>
注意,我们现在在表单元素中指定了编码类型 multipart/form-data
。这是必要的,以便浏览器以我们的服务期望的格式发送数据。
接下来,在应用中,我们创建以下端点来处理来自此表单的数据:
@POST
@Path("/example2")
public String example2(
@FormDataParam("first_name") String firstName,
@FormDataParam("last_name") String lastName,
@FormDataParam("age") String age,
@FormDataParam("photo") InputStream photo)
{
// handle form data
}
注意到每个表单字段现在都使用了 @FormDataParam
注解。我们还使用 InputStream
类型作为参数类型,用于处理二进制数据。
与前一个示例不同,每个字段及其值不再组合成字符串,而是组合成部分。每个部分由唯一的令牌分隔,使 Jersey 能轻松识别每个参数并将每个部分绑定到相应的方法参数。
例如,从这个表单发送到我们服务的原始消息可能看起来像这样:
------WebKitFormBoundarytCyB57mkvJedAHFx
Content-Disposition: form-data; name="first_name"
John
------WebKitFormBoundarytCyB57mkvJedAHFx
Content-Disposition: form-data; name="last_name"
Smith
------WebKitFormBoundarytCyB57mkvJedAHFx
Content-Disposition: form-data; name="age"
42
------WebKitFormBoundarytCyB57mkvJedAHFx
Content-Disposition: form-data; name="photo"; filename="john-smith-profile.jpeg"
Content-Type: image/jpeg
------WebKitFormBoundarytCyB57mkvJedAHFx--
这种做法的主要好处是可以一起发送文本和二进制数据。然而,与传统表单编码数据相比,它也有一些缺点。首先,只能使用 HTTP POST 方法。这是因为二进制数据不能被编码并通过 URL 字符串传递。其次,负载大小更大。如上所示,为了定义分隔符和头信息所需的额外文本,增加了比常规表单编码数据更大的体积。
5. 总结
在这篇文章中,我们研究了 Jersey 库中的两个不同注解:@FormParam
和 @FormDataParam
。这两个注解在应用程序中处理表单数据,但我们看到,它们各有不同的用途。
@FormParam
更适合发送表单编码数据,可以使用 GET 或 POST 方法,但仅限于文本字段。相反,@FormDataParam
注解处理多部分数据,包括文本和二进制数据,但仅适用于 POST 方法。
本文的所有代码示例均位于 GitHub 上。