杰瑞科技汇

Java WebService例子如何快速上手?

我们将创建一个简单的用户管理服务,包含两个操作:

Java WebService例子如何快速上手?-图1
(图片来源网络,侵删)
  1. getUserById: 根据用户ID获取用户信息。
  2. createUser: 创建一个新用户。

使用 JAX-WS (Java API for XML Web Services) - 传统方式

JAX-WS 是 Java 标准的 WebService 技术,通常与 Java EE 容器(如 Tomcat, WebLogic, JBoss)一起使用,我们将使用 JAX-WS RI (Reference Implementation),它包含在 JDK 中。

步骤 1: 创建 Maven 项目

创建一个标准的 Maven 项目,在 pom.xml 中,我们不需要添加额外的依赖,因为 JAX-WS API 和实现通常在 JDK 和运行环境中已经包含。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>jax-ws-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

步骤 2: 创建数据模型 (User.java)

package com.example.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement // 使用 JAXB 注解,方便序列化为 XML
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; }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

步骤 3: 创建 WebService 接口 (UserService.java)

package com.example.service;
import com.example.model.User;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
// @WebService: 标记这是一个 WebService 接口
@WebService
// @SOAPBinding: 定义 SOAP 消息风格
// STYLE_RPC: 使用 RPC 风格,操作名称在消息中
// STYLE_DOCUMENT: 使用文档风格,XML Schema 定义消息结构
// USE_LITERAL: 使用字面量 XML,而不是 SOAP 编码
@SOAPBinding(style = SOAPBinding.Style.RPC, use = SOAPBinding.Use.LITERAL)
public interface UserService {
    // @WebMethod: 标记这是一个 WebService 操作
    // @WebParam: 指定操作的参数名
    @WebMethod
    User getUserById(@WebParam(name = "userId") int id);
    @WebMethod
    String createUser(@WebParam(name = "user") User user);
}

步骤 4: 实现 WebService 接口 (UserServiceImpl.java)

package com.example.service;
import com.example.model.User;
import javax.jws.WebService;
// @WebService(endpointInterface = "...") 指向接口
@WebService(endpointInterface = "com.example.service.UserService")
public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(int id) {
        System.out.println("Getting user by ID: " + id);
        // 模拟从数据库获取数据
        if (id == 1) {
            return new User(1, "Alice", "alice@example.com");
        }
        return null;
    }
    @Override
    public String createUser(User user) {
        System.out.println("Creating user: " + user);
        // 模拟数据库保存操作
        return "User created successfully with ID: " + user.getId();
    }
}

步骤 5: 发布 WebService

我们可以使用一个独立的类来发布服务,也可以将其部署到 Servlet 容器(如 Tomcat),这里我们使用一个独立的发布器。

Publisher.java

Java WebService例子如何快速上手?-图2
(图片来源网络,侵删)
package com.example.publisher;
import com.example.service.UserServiceImpl;
import javax.xml.ws.Endpoint;
public class Publisher {
    public static void main(String[] args) {
        // 定义服务的访问地址
        String address = "http://localhost:8080/ws/user";
        // 创建服务实现类实例
        UserServiceImpl userService = new UserServiceImpl();
        // 发布服务
        Endpoint.publish(address, userService);
        System.out.println("WebService is published at: " + address);
    }
}

步骤 6: 测试

  1. 运行 Publisher.java

  2. 打开浏览器,访问 http://localhost:8080/ws/user?wsdl,你应该能看到生成的 WSDL (Web Services Description Language) 文件,这是一个 XML 文件,描述了你的服务接口。

  3. 使用客户端测试: 你可以使用 wsimport 命令行工具生成客户端代码,或者使用 SOAP UI 等工具。

    使用 wsimport 生成客户端:

    Java WebService例子如何快速上手?-图3
    (图片来源网络,侵删)
    # 在命令行执行,它会生成客户端代码
    wsimport -keep -p com.example.client http://localhost:8080/ws/user?wsdl

    然后编写一个客户端调用服务。


使用 Spring Boot + JAX-WS - 现代集成方式

在 Spring Boot 项目中集成 JAX-WS,需要将服务作为 Spring Bean 来管理。

步骤 1: 创建 Spring Boot 项目

使用 Spring Initializr 创建项目,添加 Spring Web 依赖。

步骤 2: 添加依赖

pom.xml 中,添加 JAX-WS 和 Servlet API 依赖(Spring Boot 版本没有自带)。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- JAX-WS API -->
    <dependency>
        <groupId>jakarta.xml.ws</groupId>
        <artifactId>jakarta.xml.ws-api</artifactId>
        <version>3.0.1</version>
    </dependency>
    <!-- JAX-WS RI (for JDK 11+) -->
    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>jaxws-rt</artifactId>
        <version>3.0.2</version>
    </dependency>
</dependencies>

步骤 3: 创建数据模型和 Service 实现代

这部分代码与 JAX-WS 示例中的 User.javaUserServiceImpl.java 完全相同。

步骤 4: 配置 Endpoint

创建一个配置类来注册我们的 WebService。

package com.example.config;
import com.example.service.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.example.model.GetUserByIdRequest;
import com.example.model.GetUserByIdResponse;
import com.example.model.CreateUserRequest;
import com.example.model.CreateUserResponse;
import jakarta.xml.ws.Endpoint;
// 注意:这里我们不再使用 @WebService 注解,而是用 Spring WS 的 @Endpoint
// 我们将手动发布 JAX-WS 服务,而不是依赖 Spring WS 的消息驱动模型
@Configuration
public class WebServiceConfig {
    @Bean
    public UserServiceImpl userService() {
        return new UserServiceImpl();
    }
    @Bean
    public Endpoint userEndpoint(UserServiceImpl userService) {
        // 创建 JAX-WS 的 Endpoint 实例
        jakarta.xml.ws.Endpoint jaxWsEndpoint = Endpoint.create(userService);
        // 可选:设置发布地址
        // jaxWsEndpoint.publish("http://localhost:8080/ws/user");
        return new SpringBootJaxWsEndpoint(jaxWsEndpoint);
    }
}
// 一个包装类,以便 Spring 能够管理它
class SpringBootJaxWsEndpoint {
    private final jakarta.xml.ws.Endpoint endpoint;
    public SpringBootJaxWsEndpoint(jakarta.xml.ws.Endpoint endpoint) {
        this.endpoint = endpoint;
    }
    @jakarta.annotation.PostConstruct
    public void init() {
        // 在应用启动后发布服务
        // 你也可以在这里设置地址,或者直接在 publisher bean 中设置
        this.endpoint.publish("http://localhost:8080/ws/user");
    }
}

注意:Spring Boot 对 JAX-WS 的支持不如对 Spring WS 的支持那么无缝,手动发布 Endpoint 是一种常见的方式。

步骤 5: 主启动类

package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JaxWsApplication {
    public static void main(String[] args) {
        SpringApplication.run(JaxWsApplication.class, args);
    }
}

步骤 6: 测试

  1. 运行 JaxWsApplication
  2. 访问 http://localhost:8080/ws/user?wsdl 查看 WSDL 文件。
  3. 测试方式与 JAX-WS 示例相同。

使用 Spring Boot + Spring Web Services - RESTful 风格

在现代微服务架构中,通常使用 RESTful 风格的 WebService(本质上是 HTTP API),而不是 SOAP,Spring Web Services 是 Spring 家族中专门用于构建契约优先(Contract-First)的 SOAP 服务的框架,而 Spring Boot + Spring MVC 则更适合构建 RESTful API。

这里我们展示如何用 Spring Boot 创建一个 RESTful API。

步骤 1: 创建 Spring Boot 项目

使用 Spring Initializr,添加 Spring Web 依赖。

步骤 2: 创建数据模型 (User.java)

package com.example.model;
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; }
}

步骤 3: 创建 Controller (UserController.java)

package com.example.controller;
import com.example.model.User;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/users") // 基础路径
public class UserController {
    // 模拟数据库
    private static final Map<Integer, User> userStore = new HashMap<>();
    static {
        userStore.put(1, new User(1, "Alice", "alice@example.com"));
    }
    // GET /api/users/{id}
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable int id) {
        User user = userStore.get(id);
        if (user != null) {
            return ResponseEntity.ok(user);
        } else {
            return ResponseEntity.notFound().build();
        }
    }
    // POST /api/users
    @PostMapping
    public ResponseEntity<String> createUser(@RequestBody User user) {
        // 简单校验
        if (user.getName() == null || user.getEmail() == null) {
            return ResponseEntity.badRequest().body("Name and Email are required.");
        }
        // 模拟生成新ID
        int newId = userStore.size() + 1;
        user.setId(newId);
        userStore.put(newId, user);
        // 返回 201 Created 状态码和创建的资源位置
        return ResponseEntity.status(HttpStatus.CREATED).body("User created with ID: " + newId);
    }
}

步骤 4: 主启动类

package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestApplication {
    public static void main(String[] args) {
        SpringApplication.run(RestApplication.class, args);
    }
}

步骤 5: 测试

  1. 运行 RestApplication

  2. 使用 curl 或 Postman 测试:

    • 获取用户 1:

      curl http://localhost:8080/api/users/1

      预期响应:

      {"id":1,"name":"Alice","email":"alice@example.com"}
    • 创建新用户:

      curl -X POST http://localhost:8080/api/users \
      -H "Content-Type: application/json" \
      -d '{"name": "Bob", "email": "bob@example.com"}'

      预期响应:

      User created with ID: 2

总结与对比

特性 JAX-WS (SOAP) Spring Boot (RESTful)
协议 SOAP (Simple Object Access Protocol) HTTP/HTTPS
数据格式 XML (严格遵循 WSDL 定义) JSON (轻量级,易读)
标准 WS-* (WS-Security, WS-Addressing 等),标准化程度高 REST (Representational State Transfer),架构风格
性能 XML 解析开销较大,通常性能较低 JSON 体积小,解析快,性能高
防火墙 SOAP 通常运行在 80/443 端口,防火墙友好 REST 使用标准 HTTP 端口,同样友好
工具生态 强大的工具支持(如 wsimport, SOAP UI) 工具丰富(Postman, Swagger),与前端无缝集成
适用场景 企业级应用、需要严格契约、高安全性要求的系统(如银行、政府) 微服务、移动后端、现代 Web 应用,追求快速开发和迭代

如何选择?

  • 如果你的系统需要与遗留的 Java EE 系统集成,或者有严格的安全和事务要求,JAX-WS 是一个可靠的选择。
  • 如果你在构建新的、现代化的应用,特别是微服务架构,Spring Boot + RESTful API (Spring MVC) 是目前的主流和首选,它更简单、更灵活、性能也更好。
分享:
扫描分享到社交APP
上一篇
下一篇