我们将主要围绕最常用的标准 JAX-WS (Java API for XML-Based Web Services) 来展开,并简要提及 JAX-RS (Java API for RESTful Web Services)。

核心概念:WebService 如何传输数组?
本质上,WebService(尤其是基于 SOAP 的)通过 XML 来传输数据,Java 数组在 XML 中通常被表示为一个列表或数组结构,最常见的形式是:
<ns2:myArray xmlns:ns2="http://ws.example.com/"> <item>元素1</item> <item>元素2</item> <item>元素3</item> </ns2:myArray>
或者,在更复杂的场景下(数组元素本身是复杂对象),它可能会被包装成一个带有特定命名空间的列表。
JAX-WS 处理数组
JAX-WS 是 Java 中创建和消费 SOAP WebService 的标准 API,处理数组非常直接。
WebService 方法接收和返回基本类型数组
这是最简单的情况,你只需要在 Java 方法中直接使用 int[], String[], double[] 等即可。

创建 WebService 接口 (SEI - Service Endpoint Interface)
import javax.jws.WebService;
import javax.jws.WebMethod;
// 使用 @WebService 注解标记这是一个 WebService 接口
@WebService
public interface ArrayWebService {
// 接收一个字符串数组,返回一个整数数组(字符串的长度)
@WebMethod
int[] getStringLengths(String[] stringArray);
// 接收一个整数数组,返回一个新的数组,每个元素都乘以2
@WebMethod
int[] multiplyByTwo(int[] numbers);
}
实现 WebService 接口
import javax.jws.WebService;
@WebService(endpointInterface = "com.example.ArrayWebService") // 指定接口
public class ArrayWebServiceImpl implements ArrayWebService {
@Override
public int[] getStringLengths(String[] stringArray) {
if (stringArray == null) {
return new int[0]; // 返回空数组
}
int[] lengths = new int[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
lengths[i] = stringArray[i] != null ? stringArray[i].length() : 0;
}
return lengths;
}
@Override
public int[] multiplyByTwo(int[] numbers) {
if (numbers == null) {
return new int[0];
}
int[] result = new int[numbers.length];
for (int i = 0; i < numbers.length; i++) {
result[i] = numbers[i] * 2;
}
return result;
}
}
发布 WebService
你可以使用 JAX-WS 内置的 API 来发布这个服务。

import javax.xml.ws.Endpoint;
public class ArrayPublisher {
public static void main(String[] args) {
// 创建服务实现类的实例
ArrayWebServiceImpl service = new ArrayWebServiceImpl();
// 发布服务到指定地址
// http://localhost:8080/ArrayWebService 是服务的访问地址
Endpoint.publish("http://localhost:8080/ArrayWebService", service);
System.out.println("WebService 已发布在 http://localhost:8080/ArrayWebService");
}
}
客户端调用
客户端可以通过 wsimport 工具生成客户端代码,然后像调用本地方法一样调用。
在命令行执行:
wsimport -p com.example.client -keep http://localhost:8080/ArrayWebService?wsdl
这会生成一堆客户端辅助类。
客户端代码可以这样写:
import com.example.client.ArrayWebService;
import com.example.client.ArrayWebServiceService;
public class ArrayClient {
public static void main(String[] args) {
// 创建服务服务视图
ArrayWebServiceService service = new ArrayWebServiceService();
// 获取 WebService 端口
ArrayWebService webService = service.getArrayWebServicePort();
// 调用方法
String[] names = {"Alice", "Bob", "Charlie"};
int[] lengths = webService.getStringLengths(names);
System.out.println("字符串长度数组: ");
for (int len : lengths) {
System.out.print(len + " "); // 输出: 5 3 7
}
System.out.println("\n");
int[] numbers = {1, 2, 3, 4, 5};
int[] doubled = webService.multiplyByTwo(numbers);
System.out.println("乘以2后的数组: ");
for (int num : doubled) {
System.out.print(num + " "); // 输出: 2 4 6 8 10
}
}
}
WebService 方法接收和返回自定义对象数组
当数组元素是复杂的 Java 对象时,JAX-WS 会自动处理这些对象的序列化和反序列化。
定义自定义对象
import javax.xml.bind.annotation.XmlRootElement;
// @XmlRootElement 是必须的,它告诉 JAXB 如何将这个类映射到 XML 根元素
@XmlRootElement
public class User {
private String name;
private int age;
private String email;
// 必须有无参构造函数
public User() {}
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// Getter 和 Setter 是必须的
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
在 WebService 接口中使用对象数组
import javax.jws.WebService;
import javax.jws.WebMethod;
import java.util.List; // JAX-WS 也支持 List
@WebService
public interface UserWebService {
@WebMethod
User[] createUsers();
@WebMethod
String processUsers(User[] users);
}
实现类
import javax.jws.WebService;
@WebService(endpointInterface = "com.example.UserWebService")
public class UserWebServiceImpl implements UserWebService {
@Override
public User[] createUsers() {
User[] users = new User[2];
users[0] = new User("John Doe", 30, "john.doe@example.com");
users[1] = new User("Jane Smith", 25, "jane.smith@example.com");
return users;
}
@Override
public String processUsers(User[] users) {
if (users == null || users.length == 0) {
return "用户列表为空。";
}
StringBuilder sb = new StringBuilder("处理了 " + users.length + " 个用户:\n");
for (User user : users) {
sb.append("- ").append(user.getName()).append(", 年龄: ").append(user.getAge()).append("\n");
}
return sb.toString();
}
}
发布和客户端调用方式与前面类似。wsimport 会自动为 User 类生成对应的客户端类。
JAX-RS (RESTful WebService) 处理数组
对于 RESTful WebService (通常基于 JSON),处理数组的方式与 JAX-WS 不同,因为它不使用 SOAP 和 WSDL,而是直接处理 HTTP 请求和响应体(通常是 JSON)。
添加依赖
你需要一个 JAX-RS 实现,Jersey 或 RESTEasy,以 Jersey 为例(Maven 依赖):
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>3.1.3</version>
</dependency>
创建资源类
使用 @Path, @POST, @GET, @Consumes, @Produces 等注解。
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.List;
@Path("/array-resource")
public class ArrayResource {
// 接收一个 JSON 数组,并返回处理后的文本
@POST
@Path("/process")
@Consumes(MediaType.APPLICATION_JSON) // 指定接收 JSON 格式的数组
@Produces(MediaType.TEXT_PLAIN)
public String processIntegerArray(int[] numbers) {
if (numbers == null) {
return "接收到的数组为 null";
}
int sum = 0;
for (int num : numbers) {
sum += num;
}
return "接收到的数组是: " + Arrays.toString(numbers) + ",它们的和是: " + sum;
}
// 返回一个 JSON 数组
@GET
@Path("/get-names")
@Produces(MediaType.APPLICATION_JSON)
public String[] getNames() {
return new String[]{"Alice", "Bob", "Charlie"};
}
// 接收一个 JSON 对象数组
@POST
@Path("/add-users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public List<User> addUsers(List<User> users) {
// 在实际应用中,这里会把 users 保存到数据库
System.out.println("服务器端收到用户列表: " + users.size());
// 返回接收到的用户列表作为确认
return users;
}
}
客户端调用 (使用 cURL)
# 调用返回数组的方法
curl -X GET "http://localhost:8080/your-app-context/array-resource/get-names" -H "Accept: application/json"
# 预期响应: ["Alice","Bob","Charlie"]
# 调用接收数组的方法
curl -X POST "http://localhost:8080/your-app-context/array-resource/process" \
-H "Content-Type: application/json" \
-d '[10, 20, 30]'
# 预期响应: 接收到的数组是: [10, 20, 30],它们的和是: 60
# 调用接收对象数组的方法
curl -X POST "http://localhost:8080/your-app-context/array-resource/add-users" \
-H "Content-Type: application/json" \
-d '[{"name":"John","age":30,"email":"john@example.com"}, {"name":"Jane","age":25,"email":"jane@example.com"}]'
# 预期响应: [{"name":"John","age":30,"email":"john@example.com"}, {"name":"Jane","age":25,"email":"jane@example.com"}]
重要注意事项和最佳实践
-
空数组 vs. null
- 最佳实践: 在代码中明确区分空数组 (
new Type[0]) 和null,返回一个空数组比返回null更安全,可以避免客户端出现NullPointerException,在服务端,如果输入为null,可以优雅地处理(如返回空数组或抛出明确的业务异常)。
- 最佳实践: 在代码中明确区分空数组 (
-
性能和大数据量
- 传输非常大的数组时,可能会遇到内存问题(OutOfMemoryError)或性能瓶颈。
- 解决方案:
- 分页/分块: 不要一次性传输整个数组,而是分页或分块传输,提供
offset和limit参数。 - 流式处理: 对于文件等大数据,可以考虑流式传输,而不是将整个文件读入内存再作为数组发送,JAX-WS 和 JAX-RS 都支持流式处理。
- 分页/分块: 不要一次性传输整个数组,而是分页或分块传输,提供
-
复杂对象数组的注解
- 在 JAX-WS 中,
@XmlRootElement通常足够了,但如果你的类无法修改,或者需要更精细的控制,可以使用@XmlType、@XmlElement等 JAXB 注解来定义 XML 映射规则。 - 如果你想改变 XML 元素的名称:
@XmlRootElement(name = "user-details") @XmlType(name = "UserType") public class User { @XmlElement(name = "full-name") private String name; // ... }
- 在 JAX-WS 中,
-
JAX-RS 中的
Listvs. 数组- 在 JAX-RS 中,
List<T>和T[]通常都可以用作方法的参数或返回类型,框架会自动将 JSON 数组反序列化为List或数组,使用List通常更灵活,尤其是在处理动态大小的数据时。
- 在 JAX-RS 中,
| 特性 | JAX-WS (SOAP) | JAX-RS (REST/JSON) |
|---|---|---|
| 核心协议 | SOAP (XML) | HTTP (JSON/XML) |
| API | @WebService, @WebMethod |
@Path, @GET, @POST, @Consumes, @Produces |
| 数组表示 | XML 列表 (<item>...</item>) |
JSON 数组 ([...]) |
| 客户端生成 | wsimport 工具 |
手动构建 HTTP 请求 或使用 Jersey Client API |
| 处理复杂对象 | 依赖 JAXB (@XmlRootElement) |
依赖 JSON-B/Jackson/Gson (通常自动处理) |
| 适用场景 | 企业级、需要契约、安全性要求高的服务 | 公开 API、移动端、前后端分离应用 |
选择哪种技术取决于你的项目需求,对于需要严格契约和 WS-* 标准的企业集成,JAX-WS 是一个强大的选择,对于现代、轻量级的 Web API,JAX-RS 是事实上的标准。
