杰瑞科技汇

Java开发Webservice接口,关键步骤与常见问题有哪些?

  1. JAX-WS (Java API for XML Web Services):这是 Java 官方推出的、较早且非常成熟的 WebService 规范,它通常基于 SOAP (Simple Object Access Protocol) 协议,使用 XML 格式进行数据交换。
  2. JAX-RS (Java API for RESTful Web Services):这是用于开发 RESTful 风格 Web 服务的 Java API,它更轻量级,通常基于 HTTP 协议,使用 JSON 或 XML 等格式进行数据交换,是目前 Web 开发的主流。

下面我将分别详细介绍这两种技术的开发流程,并提供完整的代码示例。

Java开发Webservice接口,关键步骤与常见问题有哪些?-图1
(图片来源网络,侵删)

使用 JAX-WS 开发 SOAP WebService

JAX-WS 的开发相对“传统”,但依然在很多企业级应用(如银行、政府、大型ERP系统)中广泛使用。

核心概念

  • SEI (Service Endpoint Interface):服务端点接口,一个普通的 Java 接口,定义了 WebService 提供的方法。
  • SIB (Service Implementation Bean):服务实现Bean,一个具体的 Java 类,实现了 SEI 接口,包含了业务逻辑。
  • WSDL (Web Services Description Language):一个 XML 文件,用于描述 WebService 的功能、地址、协议等信息,客户端通过 WSDL 文件来调用服务。

开发步骤

创建 Maven 项目

pom.xml 中添加 JAX-WS 的依赖,如果你使用 JDK 6+,JAX-WS API 和工具已经包含在内,但显式声明是个好习惯。

<dependencies>
    <!-- JAX-WS API -->
    <dependency>
        <groupId>javax.xml.ws</groupId>
        <artifactId>jaxws-api</artifactId>
        <version>2.3.1</version>
    </dependency>
    <!-- 为了方便测试,可以嵌入一个简单的 HTTP 服务器,如 Jetty -->
    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>jaxws-rt</artifactId>
        <version>2.3.3</version>
    </dependency>
</dependencies>

定义服务端接口 (SEI)

Java开发Webservice接口,关键步骤与常见问题有哪些?-图2
(图片来源网络,侵删)

创建一个 Java 接口,使用 @WebService 注解来标记它。

// src/main/java/com/example/webservice/HelloService.java
package com.example.webservice;
import javax.jws.WebService;
import javax.jws.WebMethod;
@WebService
public interface HelloService {
    @WebMethod
    String sayHello(String name);
}

实现服务端接口 (SIB)

创建一个实现类,实现上面的接口。

// src/main/java/com/example/webservice/HelloServiceImpl.java
package com.example.webservice;
import javax.jws.WebService;
@WebService(endpointInterface = "com.example.webservice.HelloService")
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return "Hello, " + name + "! Welcome to JAX-WS World.";
    }
}

发布 WebService

编写一个主程序,将我们的服务发布到一个指定的 URL 地址上。

// src/main/java/com/example/webservice/Publisher.java
package com.example.webservice;
import javax.xml.ws.Endpoint;
public class Publisher {
    public static void main(String[] args) {
        // 创建服务的实现实例
        HelloService serviceImpl = new HelloServiceImpl();
        // 定义服务的访问地址
        String address = "http://localhost:8888/ws/hello";
        // 发布服务
        Endpoint.publish(address, serviceImpl);
        System.out.println("WebService is published at: " + address);
        System.out.println("You can access the WSDL at: " + address + "?wsdl");
    }
}

运行和测试

  • 运行 Publishermain 方法。

  • 打开浏览器,访问 http://localhost:8888/ws/hello?wsdl,如果看到一个 XML 文件,说明服务发布成功。

  • 客户端测试:可以使用 wsimport 命令(JDK 自带)生成客户端代码进行调用。

    • 打开一个新的终端,执行:wsimport -s . http://localhost:8888/ws/hello?wsdl

    • 这会在当前目录下生成一堆客户端代码。

    • 编写一个客户端测试类:

      import com.example.webservice.HelloService;
      import com.example.webservice.HelloServiceImplService;
      public class JaxWsClient {
          public static void main(String[] args) {
              // 通过 WSDL 创建服务实例
              HelloServiceImplService service = new HelloServiceImplService();
              // 获取服务端口
              HelloService helloPort = service.getHelloServiceImplPort();
              // 调用方法
              String response = helloPort.sayHello("Alice");
              System.out.println("Client received: " + response);
          }
      }
    • 运行客户端,会得到输出:Client received: Hello, Alice! Welcome to JAX-WS World.


使用 JAX-RS (RESTful WebService) 开发

这是目前最流行的方式,特别适合移动 App、前后端分离的 Web 应用,我们以最常用的 Jersey 框架为例。

核心概念

  • JAX-RS:Java API 规范,定义了一套注解(如 @Path, @GET, @POST 等)来开发 REST 服务。
  • Jersey:是 JAX-RS 规范的参考实现,提供了完整的运行时环境和工具。
  • REST (Representational State Transfer):一种软件架构风格,强调使用标准的 HTTP 方法(GET, POST, PUT, DELETE)来操作资源。

开发步骤

创建 Maven 项目

pom.xml 中添加 Jersey 的核心依赖。

<dependencies>
    <!-- Jersey 核心依赖 -->
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-http</artifactId>
        <!-- 使用最新稳定版 -->
        <version>2.41</version>
    </dependency>
    <!-- 如果需要支持 JSON,需要添加这个依赖 -->
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>2.41</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-binding</artifactId>
        <version>2.41</version>
    </dependency>
</dependencies>

定义资源类

使用 @Path 注解标记一个类作为资源类,使用 @GET, @POST 等注解标记方法。

// src/main/java/com/example/rest/ResourceConfig.java
package com.example.rest;
import org.glassfish.jersey.server.ResourceConfig;
// 自定义 ResourceConfig,注册我们的资源
public class ResourceConfig extends org.glassfish.jersey.server.ResourceConfig {
    public ResourceConfig() {
        // 扫描并注册 com.example.rest 包下的所有资源
        packages("com.example.rest");
    }
}
// src/main/java/com/example/rest/UserResource.java
package com.example.rest;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
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<>();
    private static int idCounter = 1;
    // GET /users - 获取所有用户列表
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<User> getAllUsers() {
        return new ArrayList<>(userDB.values());
    }
    // GET /users/{id} - 根据ID获取单个用户
    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public User getUserById(@PathParam("id") int id) {
        return userDB.get(id);
    }
    // POST /users - 创建一个新用户
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public User createUser(User user) {
        user.setId(idCounter++);
        userDB.put(user.getId(), user);
        return user; // 返回创建成功的用户对象(包含ID)
    }
}
// 用户实体类
class User {
    private int id;
    private String name;
    private String 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; }
}

启动服务器并发布资源

编写一个主程序来启动 Grizzly 服务器。

// src/main/java/com/example/rest/ServerLauncher.java
package com.example.rest;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import java.net.URI;
public class ServerLauncher {
    public static final String BASE_URI = "http://localhost:8080/api/";
    public static void main(String[] args) {
        // 创建 ResourceConfig 实例
        final ResourceConfig rc = new ResourceConfig();
        // 或者直接注册资源类: rc.registerClasses(UserResource.class);
        // 创建并启动 Grizzly HTTP 服务器
        HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
        System.out.println("Jersey app started with WADL available at "
                + BASE_URI + "application.wadl\nHit enter to stop it...");
        try {
            System.in.read();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.shutdownNow();
        }
    }
}

运行和测试

  • 运行 ServerLaunchermain 方法。

  • 服务启动后,你可以使用任何 API 测试工具(如 Postman, Insomnia, curl)来测试接口。

    • 获取所有用户:

      • GET http://localhost:8080/api/users
      • 预期返回: [] (空列表)
    • 创建用户:

      • POST http://localhost:8080/api/users
      • Body 中选择 raw -> JSON,输入:
        {
            "name": "Bob",
            "email": "bob@example.com"
        }
      • 预期返回 (状态码 201 Created):
        {
            "id": 1,
            "name": "Bob",
            "email": "bob@example.com"
        }
    • 获取ID为1的用户:

      • GET http://localhost:8080/api/users/1
      • 预期返回:
        {
            "id": 1,
            "name": "Bob",
            "email": "bob@example.com"
        }

方案对比与选择

特性 JAX-WS (SOAP) JAX-RS (REST)
协议 SOAP (基于XML,有严格规范) HTTP (无状态,灵活)
数据格式 XML (默认) JSON (主流), XML, Text 等
风格 面向接口/操作 面向资源
标准/规范 WSDL, UDDI (发现服务) 无标准,但有 RESTful 设计原则
安全性 内置 WS-Security 标准 通常依赖 OAuth 2.0, JWT, HTTPS
性能 SOAP 头部等开销较大,性能较低 轻量级,性能高
适用场景 企业级应用、金融、政府、需要高安全性和事务保证的场景 Web API、移动后端、微服务、前后端分离项目
开发体验 相对繁琐,需要工具生成客户端代码 简单直观,符合 Web 开发习惯

如何选择?

  • 选择 JAX-RS (REST):如果你的项目是现代的 Web 应用,需要与移动端或前端交互,或者你正在构建微服务,毫不犹豫地选择 REST,它更简单、更高效、更符合当前的技术潮流。
  • 选择 JAX-WS (SOAP):如果你的项目需要与一些老旧的、基于 SOAP 的企业系统(如 SAP, Oracle EBS)集成,或者你的组织对安全性有非常严格且标准化的要求(如 WS-Security),SOAP 仍然是一个可靠的选择。

其他重要概念

  • 框架集成:在实际项目中,我们通常不会自己写服务器启动代码,REST 服务可以轻松集成到 Spring Boot 中,SOAP 服务可以集成到 SpringSpring Boot 中,由框架管理生命周期,这会大大简化开发。
  • 安全性:无论是 REST 还是 SOAP,安全都是重中之重,REST 常用 JWT (JSON Web Tokens)OAuth 2.0 进行身份认证和授权,SOAP 则使用 WS-Security
  • 文档:REST 服务通常使用 Swagger (OpenAPI) 来自动生成和提供交互式 API 文档,这对于前后端协作至关重要,SOAP 服务则依赖 WSDL 文档。

希望这份详细的指南能帮助你从零开始掌握 Java WebService 接口开发!

分享:
扫描分享到社交APP
上一篇
下一篇