WebService 是一种跨编程语言、跨操作系统的远程调用技术,它使用 XML、SOAP (Simple Object Access Protocol)、WSDL (Web Services Description Language) 等标准协议,使得不同平台的应用程序能够相互通信。

在 Java 生态中,实现 WebService 主要有两种主流技术栈:
- JAX-WS (Java API for XML Web Services):这是 Java 官方推出的、较为传统的 WebService 规范,它简化了基于 SOAP 的 WebService 开发,从 Java 6 开始,JAX-WS 就已经作为标准内置在 JDK 中了。
- JAX-RS (Java API for RESTful Web Services):这是用于构建 RESTful 风格 Web 服务的规范,虽然严格来说 RESTful 服务不总是符合 WebService 的经典定义(基于 SOAP/WSDL),但在现代开发中,它已经成为 WebService(特别是面向客户端/前端的服务)的事实标准。
下面我将分别对这两种技术进行详细说明,并提供完整的代码示例。
JAX-WS (SOAP WebService)
JAX-WS 适用于需要高安全性、事务性、可靠性的企业级应用,通常通过 SOAP 协议在 HTTP/HTTPS 上传输数据。
核心概念
- Endpoint (端点):Web 服务的访问地址,是一个 URL。
- SEI (Service Endpoint Interface):服务端接口,定义了 Web 服务提供的所有方法。
- SIB (Service Implementation Bean):服务端实现类,实现了 SEI 接口。
- WSDL (Web Services Description Language):一个 XML 文件,用于描述 Web 服务的功能、方法、参数、返回值以及访问地址等,客户端通过 WSDL 文件来了解如何调用服务。
- SOAP (Simple Object Access Protocol):一种基于 XML 的协议,用于在 Web 上交换结构化的信息。
开发步骤 (使用 JAX-WS 注解)
环境准备

- JDK 1.6 或更高版本 (JDK 内置了 JAX-WS API)
- 构建工具 (Maven/Gradle,推荐使用)
示例:创建一个简单的天气查询 WebService
步骤 1:创建 Maven 项目
在 pom.xml 中添加依赖(虽然 JAX-WS 在 JDK 中,但为了方便编译和运行,我们通常使用 jaxws-rt)。
<dependencies>
<!-- JAX-WS 运行时环境 -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
步骤 2:创建服务端接口 (SEI)
// src/main/java/com/example/WeatherService.java
package com.example;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
// @WebService 注解将一个类标记为 WebService
@WebService
// @SOAPBinding 定义 SOAP 消息风格,默认是 DOCUMENT
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public interface WeatherService {
// @WebMethod 将一个方法暴露为 WebService 的操作
@WebMethod
String getWeather(String city);
}
步骤 3:创建服务端实现类 (SIB)
// src/main/java/com/example/WeatherServiceImpl.java
package com.example;
import javax.jws.WebService;
// @WebService 注解必须加上,并指定 endpointInterface 指向接口
@WebService(endpointInterface = "com.example.WeatherService")
public class WeatherServiceImpl implements WeatherService {
@Override
public String getWeather(String city) {
// 模拟业务逻辑
if ("北京".equals(city)) {
return "晴天,25°C";
} else if ("上海".equals(city)) {
return "多云,28°C";
} else {
return "未知城市,请检查输入";
}
}
}
步骤 4:发布 WebService
我们可以编写一个 main 方法来发布服务。
// src/main/java/com/example/WeatherPublisher.java
package com.example;
import javax.xml.ws.Endpoint;
public class WeatherPublisher {
public static void main(String[] args) {
// 定义服务的访问地址
String address = "http://localhost:8888/weather";
// 发布服务
Endpoint.publish(address, new WeatherServiceImpl());
System.out.println("WebService 已发布成功!");
System.out.println("访问地址: " + address + "?wsdl");
}
}
运行 WeatherPublisher 的 main 方法,你的 WebService 已经成功发布在 http://localhost:8888/weather。

步骤 5:访问 WSDL 和测试
在浏览器中访问 http://localhost:8888/weather?wsdl,你会看到一个 XML 文件,这就是 WSDL,它描述了你的服务如何被调用。
测试方式一:使用 wsimport 命令生成客户端
打开一个新的命令行窗口,执行以下命令(确保你的服务正在运行):
# -p: 客户端包名 # -d: 生成的class文件存放目录 # -s: 生成的java源文件存放目录 wsimport -p com.example.client -d . -s . http://localhost:8888/weather?wsdl
执行后,会在指定目录下生成一堆客户端代码(.java 和 .class 文件)。
测试方式二:编写客户端代码
使用生成的客户端代码调用服务。
// src/main/java/com/example/client/WeatherClient.java
package com.example.client;
import com.example.WeatherService;
import com.example.WeatherServiceImplService;
public class WeatherClient {
public static void main(String[] args) {
// 通过 WSDL 地址创建服务实例
WeatherServiceImplService service = new WeatherServiceImplService();
// 获取服务端点接口 (SEI) 的代理对象
WeatherService weatherService = service.getWeatherServiceImplPort();
// 调用远程方法
String weatherInfo = weatherService.getWeather("北京");
System.out.println("北京的天气: " + weatherInfo);
weatherInfo = weatherService.getWeather("广州");
System.out.println("广州的天气: " + weatherInfo);
}
}
运行 WeatherClient,即可看到从服务端返回的结果。
JAX-RS (RESTful WebService)
RESTful 是一种基于 HTTP 协议的设计风格,而不是一个像 SOAP 那样的严格协议,它更轻量、更易于理解和使用,是目前 Web 开发(特别是前后端分离)的主流方式。
核心概念
- 资源:REST 的核心是资源,一切皆资源,用户、订单、文章都是资源。
- URI:统一资源标识符,用于唯一标识一个资源。
/users/123。 - HTTP 方法:
GET:获取资源POST:创建资源PUT:更新资源(全量)DELETE:删除资源PATCH:更新资源(部分)
- 数据格式:通常使用 JSON 或 XML,JSON 是目前最主流的选择。
开发步骤 (使用 JAX-RS 注解,以 Jersey 为例)
Jersey 是 JAX-RS 规范最流行的开源实现之一。
环境准备
- JDK
- Maven
示例:创建一个用户管理的 RESTful 服务
步骤 1:创建 Maven 项目
在 pom.xml 中添加 Jersey 依赖。
<dependencies>
<!-- Jersey 核心依赖 -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.39</version>
</dependency>
<!-- 为了支持 JSON,需要添加这个依赖 -->
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.39</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-binding</artifactId>
<version>2.39</version>
</dependency>
</dependencies>
<!-- 配置 Jetty 或 Tomcat 插件,方便运行 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>11.0.15</version>
<configuration>
<webApp>
<contextPath>/api</contextPath>
</webApp>
<httpConnector>
<port=8080</port>
</httpConnector>
</configuration>
</plugin>
</plugins>
</build>
步骤 2:创建资源类
// src/main/java/com/example/UserResource.java
package com.example;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;
// @Path 注解定义资源的基 URI
@Path("/users")
public class UserResource {
// 模拟一个数据库
private static final Map<Integer, User> userDB = new HashMap<>();
static {
userDB.put(1, new User(1, "张三"));
userDB.put(2, new User(2, "李四"));
}
// @GET: 处理 HTTP GET 请求
// @Path: 定义子路径
// @Produces: 指定返回的媒体类型
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getUserById(@PathParam("id") int id) {
User user = userDB.get(id);
if (user == null) {
// 返回 404 Not Found
return Response.status(Response.Status.NOT_FOUND).entity("用户不存在").build();
}
// 返回 200 OK 和用户对象(Jersey 会自动转换为 JSON)
return Response.ok(user).build();
}
// @GET: 获取所有用户
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<User> getAllUsers() {
return new ArrayList<>(userDB.values());
}
// @POST: 创建新用户
// @Consumes: 指定接收请求体的媒体类型
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createUser(User user) {
// 简单校验
if (user.getName() == null || user.getName().isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST).entity("用户名不能为空").build();
}
// 生成新ID (简单模拟)
int newId = userDB.size() + 1;
user.setId(newId);
userDB.put(newId, user);
// 返回 201 Created 和新创建的资源
return Response.status(Response.Status.CREATED).entity(user).build();
}
}
// User 实体类
class User {
private int id;
private String name;
// 无参构造函数是 JSON 序列化/反序列化所必需的
public User() {}
public User(int id, String name) {
this.id = id;
this.name = name;
}
// Getter 和 Setter
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
步骤 3:配置 Jersey
创建一个配置类来注册资源。
// src/main/java/com/example/MyApplication.java
package com.example;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ApplicationPath;
// @ApplicationPath 定义整个 JAX-RS 应用的根路径
@ApplicationPath("/rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
// 注册资源类
registerClasses(UserResource.class);
}
}
步骤 4:配置 web.xml
在 src/main/webapp/WEB-INF/web.xml 中配置 Servlet。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
步骤 5:运行和测试
使用 Maven Jetty 插件运行项目:mvn jetty:run
测试 API (使用 Postman 或 curl)
-
获取所有用户
- URL:
http://localhost:8080/api/rest/users - Method:
GET - Response (JSON):
[ {"id":1,"name":"张三"}, {"id":2,"name":"李四"} ]
- URL:
-
获取指定 ID 用户
- URL:
http://localhost:8080/api/rest/users/1 - Method:
GET - Response (JSON):
{"id":1,"name":"张三"}
- URL:
-
创建新用户
- URL:
http://localhost:8080/api/rest/users - Method:
POST - Header:
Content-Type: application/json - Body (raw, JSON):
{"name":"王五"} - Response (JSON):
{"id":3,"name":"王五"}
- URL:
JAX-WS vs. JAX-RS (SOAP vs. REST)
| 特性 | JAX-WS (SOAP) | JAX-RS (REST) |
|---|---|---|
| 协议 | 强制使用 SOAP 协议 | 基于 HTTP 协议,无强制协议 |
| 数据格式 | 默认使用 XML,也支持其他 | 默认使用 JSON,也支持 XML 等 |
| 描述语言 | WSDL (Web Services Description Language) | 通常没有,API 文档通过 Swagger/OpenAPI 等生成 |
| 风格 | 面向行为和操作 | 面向资源和资源状态 |
| 耦合度 | 高度耦合,标准和规范严格 | 松散耦合,更灵活 |
| 性能 | 协议开销大,性能相对较低 | 协议开销小,性能高 |
| 安全性 | 内置了 WS-Security 等安全标准 | 通常依赖 HTTPS 和 OAuth2 等标准 |
| 适用场景 | 企业级应用、金融、电信等对安全性和事务性要求高的场景 | 移动应用、前后端分离的 Web 应用、公开 API |
- 如果你需要构建一个遵循传统企业级标准、对安全性和事务性有极高要求的跨平台服务,JAX-WS (SOAP) 是一个选择。
- 如果你正在开发现代的、面向互联网的应用,特别是需要与移动端或前端框架(如 React, Vue)高效对接,JAX-RS (RESTful) 是绝对的主流和首选,它更简单、更快速、更符合 Web 的本质。
在大多数新的 Java 项目中,你遇到和使用的几乎都是 JAX-RS。
