- JAX-WS (Java API for XML Web Services):这是目前最主流、最标准的 Java WebService 开发技术,用于构建 SOAP (Simple Object Access Protocol) 风格的 WebService,它通常与 Java EE (Jakarta EE) 一起使用,在 Java 6 之后已经内置了运行时环境。
- JAX-RS (Java API for RESTful Web Services):这是用于构建 REST (Representational State Transfer) 风格 WebService 的标准,REST 风格更轻量级,通常使用 JSON 或 XML 作为数据交换格式,目前在移动端和前后端分离架构中非常流行。
下面我将分别详细介绍如何使用这两种技术创建 WebService,并提供完整的示例。

使用 JAX-WS 创建 SOAP WebService
这种方式的核心是定义一个服务接口(SEI - Service Endpoint Interface)和一个实现类(SIB - Service Implementation Bean)。
环境准备
- JDK: 1.6 或更高版本。
- Web 容器: Tomcat, Jetty, 或者 Java EE 应用服务器如 JBoss/WildFly, WebLogic。
- IDE: IntelliJ IDEA 或 Eclipse。
开发步骤
步骤 1:创建一个标准的 Java Web 项目
在 IDE (如 Eclipse) 中,创建一个 "Dynamic Web Project"。
步骤 2:编写服务接口 (SEI)

这个接口定义了 WebService 提供的方法,需要使用 @WebService 注解来标记它。
// src/com/example/service/UserService.java
package com.example.service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
// @WebService: 定义这是一个WebService接口
// name: 服务名
// targetNamespace: 命名空间,通常使用包名的反序
@WebService(name = "UserService", targetNamespace = "http://service.example.com/")
// @SOAPBinding: 定义SOAP消息的风格
// SOAPBinding.Style.DOCUMENT: 使用文档风格的SOAP消息
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public interface UserService {
// @WebMethod: 定义这是一个WebService方法
// @WebParam: 定义方法的参数名
@WebMethod
String sayHello(@WebParam(name = "username") String name);
@WebMethod
User getUserById(@WebParam(name = "userId") int id);
}
步骤 3:编写服务实现类 (SIB)
这个类实现了上面定义的接口,并使用 @WebService 注解标记。
// src/com/example/service/impl/UserServiceImpl.java
package com.example.service.impl;
import com.example.service.UserService;
import com.example.model.User;
import javax.jws.WebService;
// @WebService: 定义这是一个WebService实现类
// endpointInterface: 指定它实现的接口
@WebService(endpointInterface = "com.example.service.UserService")
public class UserServiceImpl implements UserService {
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
@Override
public User getUserById(int id) {
// 模拟从数据库获取用户
if (id == 1) {
return new User(1, "John Doe", "john.doe@example.com");
} else {
return new User(0, "Unknown User", "unknown@example.com");
}
}
}
步骤 4:创建一个简单的 POJO (数据模型)

WebService 方法可以返回自定义对象。
// src/com/example/model/User.java
package com.example.model;
import javax.xml.bind.annotation.XmlRootElement;
// @XmlRootElement: 告诉JAX-WS如何将这个对象序列化为XML
@XmlRootElement
public class User {
private int id;
private String name;
private String email;
// 必须有一个无参构造函数
public User() {}
public User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getters and Setters
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; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
步骤 5:发布 WebService
你需要一个发布器来将你的服务暴露给网络,最常用的发布器是 Apache CXF 或 Metro,这里以 Apache CXF 为例。
-
添加 CXF 依赖: 如果你使用 Maven,在
pom.xml中添加 CXF 依赖:<dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.4.5</version> <!-- 使用最新稳定版 --> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>3.4.5</version> </dependency> </dependencies> -
创建发布类: 在
src目录下创建一个类来启动一个内嵌的 Jetty 服务器并发布你的服务。// src/com/example/publisher/UserServicePublisher.java package com.example.publisher; import com.example.service.impl.UserServiceImpl; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; public class UserServicePublisher { public static void main(String[] args) { // 1. 创建 JaxWsServerFactoryBean JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean(); // 2. 设置服务实现类 factory.setServiceClass(UserServiceImpl.class); // 3. 设置服务地址 (URL) factory.setAddress("http://localhost:8080/ws/user"); // 4. 创建并启动服务 factory.create(); System.out.println("WebService published successfully!"); System.out.println("Service WSDL is available at: http://localhost:8080/ws/user?wsdl"); } }
步骤 6:测试 WebService
- 运行发布类: 右键点击
UserServicePublisher.java,选择 "Run as" -> "Java Application"。 - 访问 WSDL: 打开浏览器,访问
http://localhost:8080/ws/user?wsdl,如果能看到 XML 内容,说明发布成功。 - 使用客户端测试:
你可以使用 IDE 的 WebService 客户端功能,或者使用
wsimport命令生成客户端代码进行测试。
使用 JAX-RS 创建 REST WebService
这种方式更侧重于资源(Resources)的操作,通常与 Jersey (参考实现) 或 RESTEasy 一起使用。
环境准备
- JDK: 1.7 或更高版本。
- Web 容器: Tomcat, Jetty。
- IDE: IntelliJ IDEA 或 Eclipse。
- JAX-RS 实现: Jersey 或 RESTEasy,这里以 Jersey 为例。
开发步骤
步骤 1:创建一个标准的 Java Web 项目
步骤 2:添加 Jersey 依赖
如果你使用 Maven,在 pom.xml 中添加 Jersey 依赖:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.39</version> <!-- 使用最新稳定版 -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.39</version>
</dependency>
</dependencies>
步骤 3:配置 web.xml
告诉容器如何处理 JAX-RS 请求。
<!-- web.xml -->
<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>jersey.config.server.provider.packages</param-name>
<param-value>com.example.resource</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
步骤 4:创建资源类
这是 REST 服务的核心,使用 @Path, @GET, @POST, @Produces, @Consumes 等注解来定义端点。
// src/com/example/resource/UserResource.java
package com.example.resource;
import com.example.model.User;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Path("/users") // 定义基础路径
public class UserResource {
// 模拟一个数据库
private static final ConcurrentMap<Integer, User> userDB = new ConcurrentHashMap<>();
static {
userDB.put(1, new User(1, "Alice", "alice@example.com"));
userDB.put(2, new User(2, "Bob", "bob@example.com"));
}
// @GET: 处理 HTTP GET 请求
// @Produces: 指定返回的媒体类型 (这里返回JSON)
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<User> getAllUsers() {
return new ArrayList<>(userDB.values());
}
// @Path: 定义更具体的路径
// @GET: 处理 HTTP GET 请求
// @Produces: 指定返回的媒体类型
// @PathParam: 从路径中获取参数
@GET
@Path("/{userId}")
@Produces(MediaType.APPLICATION_JSON)
public Response getUserById(@PathParam("userId") int userId) {
User user = userDB.get(userId);
if (user == null) {
// 如果用户不存在,返回 404 Not Found
return Response.status(Response.Status.NOT_FOUND).entity("User not found").build();
}
// 返回 200 OK 和用户对象
return Response.ok(user).build();
}
// @POST: 处理 HTTP POST 请求
// @Consumes: 指定接收的媒体类型 (这里接收JSON)
// @Produces: 指定返回的媒体类型
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createUser(User user) {
// 简单校验
if (user.getName() == null || user.getEmail() == null) {
return Response.status(Response.Status.BAD_REQUEST).entity("Name and Email are required").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();
}
}
步骤 5:部署和测试
-
部署项目: 将项目打包成 WAR 文件,并部署到 Tomcat 或其他 Web 容器中。
-
启动服务器。
-
使用 API 测试工具 (如 Postman, curl) 或浏览器进行测试:
-
获取所有用户:
- URL:
http://localhost:8080/YourProjectName/api/users - Method:
GET - 预期响应 (JSON):
[ { "id": 1, "name": "Alice", "email": "alice@example.com" }, { "id": 2, "name": "Bob", "email": "bob@example.com" } ]
- URL:
-
获取单个用户 (ID=1):
- URL:
http://localhost:8080/YourProjectName/api/users/1 - Method:
GET - 预期响应 (JSON):
{ "id": 1, "name": "Alice", "email": "alice@example.com" }
- URL:
-
创建新用户:
- URL:
http://localhost:8080/YourProjectName/api/users - Method:
POST - Headers:
Content-Type: application/json - Body (raw, JSON):
{ "name": "Charlie", "email": "charlie@example.com" } - 预期响应 (JSON, 状态码 201):
{ "id": 3, "name": "Charlie", "email": "charlie@example.com" }
- URL:
-
总结与对比
| 特性 | JAX-WS (SOAP) | JAX-RS (REST) |
|---|---|---|
| 协议 | SOAP (基于 XML) | HTTP (通常用 JSON) |
| 标准 | Java EE 内置标准 | Java EE 内置标准 |
| 风格 | 面向操作 | 面向资源 |
| 格式 | 严格定义的 WSDL 和 XSD | 灵活的 JSON/XML |
| 安全性 | 内置 WS-Security 等标准 | 通常依赖 HTTP(S) 安全 |
| 适用场景 | 企业级应用、金融、电信等需要强契约和安全性的场景 | 移动后端、Web API、前后端分离项目 |
| 实现框架 | Metro (JDK内置), Apache CXF | Jersey, RESTEasy, Apache CXF |
| 优点 | 契约优先、跨语言、安全性强 | 轻量、简单、易于理解、性能好、与 HTTP 无缝集成 |
| 缺点 | 协议复杂、冗余、调试困难 | 无统一标准、安全性实现需自行处理 |
如何选择?
- 如果你的系统需要与传统的、基于 SOAP 的企业系统(如 .NET, SAP)集成,或者对安全性和事务性有非常严格的要求,选择 JAX-WS。
- 如果你在构建现代化的 Web 应用或移动应用后端,追求开发效率、性能和灵活性,并且前后端分离是架构的核心,JAX-RS 是更好的选择,REST 的应用场景远比 SOAP 广泛。
