杰瑞科技汇

Java webservice接口如何调用与调试?

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

Java webservice接口如何调用与调试?-图1
(图片来源网络,侵删)

在 Java 生态中,实现 WebService 主要有两种主流技术栈:

  1. JAX-WS (Java API for XML Web Services):这是 Java 官方推出的、较为传统的 WebService 规范,它简化了基于 SOAP 的 WebService 开发,从 Java 6 开始,JAX-WS 就已经作为标准内置在 JDK 中了。
  2. 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 注解)

环境准备

Java webservice接口如何调用与调试?-图2
(图片来源网络,侵删)
  • 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");
    }
}

运行 WeatherPublishermain 方法,你的 WebService 已经成功发布在 http://localhost:8888/weather

Java webservice接口如何调用与调试?-图3
(图片来源网络,侵删)

步骤 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)

  1. 获取所有用户

    • URL: http://localhost:8080/api/rest/users
    • Method: GET
    • Response (JSON):
      [
          {"id":1,"name":"张三"},
          {"id":2,"name":"李四"}
      ]
  2. 获取指定 ID 用户

    • URL: http://localhost:8080/api/rest/users/1
    • Method: GET
    • Response (JSON):
      {"id":1,"name":"张三"}
  3. 创建新用户

    • URL: http://localhost:8080/api/rest/users
    • Method: POST
    • Header: Content-Type: application/json
    • Body (raw, JSON):
      {"name":"王五"}
    • Response (JSON):
      {"id":3,"name":"王五"}

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

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