杰瑞科技汇

Java webservice如何高效传输对象?

在 Java WebService 的世界里,“对象”通常指代两种核心实体:

Java webservice如何高效传输对象?-图1
(图片来源网络,侵删)
  1. 客户端(Consumer):调用远程服务的应用程序。
  2. 服务端(Provider):提供服务的应用程序。

这两个“对象”通过标准的 WebService 协议(如 SOAP 或 RESTful)进行交互,下面我将分点详细阐述,并重点介绍如何在这些对象之间传递自定义的 Java 对象。


核心概念:客户端 vs. 服务端

1 WebService 服务端

服务端是“生产者”,它定义了一个或多个可以被远程调用的方法,这些方法可以接收参数、执行业务逻辑,并返回结果,这些参数和结果可以是基本数据类型(如 String, int),也可以是复杂的自定义 Java 对象。

主要技术栈:

  • JAX-WS (Java API for XML Web Services):这是 Java 官方、标准的 SOAP WebService 开发框架,非常成熟稳定,广泛用于企业级应用。
  • JAX-RS (Java API for RESTful Web Services):这是用于开发 RESTful 风格 WebService 的标准,虽然更侧重于资源,但它也是 WebService 的一种重要形式,并且处理对象的方式与 JAX-WS 不同。

2 WebService 客户端

客户端是“消费者”,它通过网络找到服务端,调用其提供的方法,并处理返回的结果,客户端需要知道服务端的“地址”和“接口规范”(即 WSDL 文件)才能正确地调用。

Java webservice如何高效传输对象?-图2
(图片来源网络,侵删)

主要技术栈:

  • JAX-WS 客户端:通常通过 wsimport 工具根据 WSDL 文件生成客户端代码(存根/代理),然后像调用本地方法一样调用远程方法。
  • JAX-RS 客户端:通常使用 Jersey、RestEasy 等框架提供的 API,通过 HTTP 请求(如 GET, POST, PUT, DELETE)来访问 REST 资源。

核心问题:如何在 WebService 中传递 Java 对象?

这是问题的核心,由于 WebService 是基于网络通信的,而网络只能传输文本(如 XML 或 JSON),因此不能直接传输 Java 对象,必须将 Java 对象序列化成一种标准格式的文本,传输到对方后,再反序列化成对方语言(通常是 Java)的对象。

1 基于 SOAP (JAX-WS) 的对象传递

SOAP 协议默认使用 XML 作为数据交换格式,JAX-WS 框架会自动处理 Java 对象与 XML 之间的转换,这个过程称为 XML Binding

工作原理:

Java webservice如何高效传输对象?-图3
(图片来源网络,侵删)
  1. 服务端:你定义一个方法,参数是一个自定义的 Java 对象(User 对象),JAX-WS 在处理请求时,会自动将这个 User 对象序列化为符合特定 Schema(XSD)的 XML 文档。
  2. 网络传输:这个 XML 文档作为 SOAP 消息的一部分被发送给客户端。
  3. 客户端:客户端接收到 SOAP 消息后,JAX-WS 会根据 WSDL 中定义的 Schema,自动将 XML 文档反序列化成对应的 User 对象。

关键步骤:

  1. 创建 Java 对象 (POJO): 这个对象必须是一个标准的 JavaBean,即有无参构造函数,并且属性有 gettersetter 方法。

    // User.java
    public class User {
        private String name;
        private int age;
        // 必须有无参构造函数
        public User() {
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
  2. 在服务端接口中使用该对象: 使用 @WebService 注解定义服务端接口。

    import javax.jws.WebService;
    import javax.jws.WebMethod;
    @WebService
    public interface UserService {
        @WebMethod
        public String getGreeting(User user);
    }
  3. 实现服务端接口

    import javax.jws.WebService;
    @WebService(endpointInterface = "com.example.UserService")
    public class UserServiceImpl implements UserService {
        @Override
        public String getGreeting(User user) {
            return "Hello, " + user.getName() + "! You are " + user.getAge() + " years old.";
        }
    }
  4. 发布服务: 使用 Endpoint 类将服务发布到某个 URL。

    import javax.xml.ws.Endpoint;
    public class Publisher {
        public static void main(String[] args) {
            UserServiceImpl userService = new UserServiceImpl();
            Endpoint.publish("http://localhost:8080/userService", userService);
            System.out.println("UserService is published at http://localhost:8080/userService");
        }
    }
  5. 客户端调用

    • 生成客户端代码:在命令行运行 wsimport -keep http://localhost:8080/userService?wsdl,这会生成一堆 Java 文件,包括一个 User 类(和你的类同名或类似)和一个 UserService 接口。

    • 使用客户端代码

      import com.example.UserService;
      import com.example.User;
      import javax.xml.ws.Service;
      import java.net.URL;
      public class Client {
          public static void main(String[] args) throws Exception {
              URL wsdlUrl = new URL("http://localhost:8080/userService?wsdl");
              QName qname = new QName("http://example.com/", "UserService");
              Service service = Service.create(wsdlUrl, qname);
              UserService userService = service.getPort(UserService.class);
              // 创建客户端 User 对象
              User user = new User();
              user.setName("Alice");
              user.setAge(30);
              // 调用远程方法,对象会自动序列化
              String response = userService.getGreeting(user);
              System.out.println(response); // 输出: Hello, Alice! You are 30 years old.
          }
      }

2 基于 RESTful (JAX-RS) 的对象传递

RESTful WebService 通常使用 JSON 作为数据交换格式,因为它比 XML 更轻量、更易于解析,JAX-RS 框架(如 Jersey)会自动处理 Java 对象与 JSON 之间的转换。

工作原理:

  1. 服务端:你定义一个资源方法,接收一个 JSON 格式的请求体,JAX-RS 框架(如 Jackson, Gson)会自动将这个 JSON 字符串反序列化成 Java 对象。
  2. 网络传输:HTTP 请求的 Body 部分是 JSON 格式的数据。
  3. 服务端返回:方法返回一个 Java 对象,JAX-RS 框架会自动将其序列化为 JSON 字符串,并作为 HTTP 响应的 Body 发送给客户端。

关键步骤 (以 Jersey 为例):

  1. 添加依赖:确保你的项目包含 Jersey 和 JSON 处理库(如 jersey-media-json-jackson)的依赖。

  2. 创建 Java 对象 (POJO):和 JAX-WS 一样,需要一个标准的 JavaBean。

    // User.java
    public class User {
        private String name;
        private int age;
        public User() {}
        // getters and setters...
    }
  3. 创建资源类: 使用 @Path, @POST, @Consumes, @Produces 等注解。

    import javax.ws.rs.*;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    @Path("/users")
    public class UserResource {
        // 接收一个 JSON,并将其映射为 User 对象
        @POST
        @Consumes(MediaType.APPLICATION_JSON) // 声明接收 JSON
        @Produces(MediaType.APPLICATION_JSON) // 声明返回 JSON
        public Response createUser(User user) {
            // 业务逻辑...
            System.out.println("Received user: " + user.getName());
            // 返回一个创建成功的响应,可以包含新创建的用户信息
            user.setName("Created: " + user.getName());
            return Response.status(201).entity(user).build();
        }
    }
  4. 客户端调用: 客户端可以使用 Jersey 客户端 API、Apache HttpClient 或其他 HTTP 客户端工具。

    import javax.ws.rs.client.Client;
    import javax.ws.rs.client.ClientBuilder;
    import javax.ws.rs.client.Entity;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    public class RestClient {
        public static void main(String[] args) {
            Client client = ClientBuilder.newClient();
            // 创建要发送的 User 对象
            User user = new User();
            user.setName("Bob");
            user.setAge(25);
            // 发送 POST 请求,User 对象会被自动序列化为 JSON
            Response response = client.target("http://localhost:8080/myapp/users")
                                      .request(MediaType.APPLICATION_JSON)
                                      .post(Entity.json(user));
            // 从响应中获取返回的 User 对象(自动从 JSON 反序列化)
            User createdUser = response.readEntity(User.class);
            System.out.println("Status: " + response.getStatus());
            System.out.println("Created User: " + createdUser.getName());
            response.close();
            client.close();
        }
    }

总结与对比

特性 JAX-WS (SOAP) JAX-RS (RESTful)
协议 SOAP (XML) HTTP (通常用 JSON)
数据格式 XML JSON (也支持 XML, HTML等)
核心思想 动作导向 (RPC-like) 资源导向
对象传递 自动与 XML 序列化/反序列化 自动与 JSON 序列化/反序列化
客户端调用 wsimport 生成客户端存根 直接使用 HTTP 客户端 API
优点 标准化、安全、有契约 (WSDL) 简单、轻量、易于与前端集成
缺点 协议复杂、冗余 无统一标准,依赖具体实现
适用场景 企业级应用、B2B 集成、需要强契约和安全的场景 移动应用、前后端分离、微服务

重要注意事项

  1. 对象的可序列化:对于 JAX-WS 和 JAX-RS,你的 JavaBean 最好实现 java.io.Serializable 接口,虽然不总是强制要求,但这是一个好习惯,尤其是在涉及分布式系统时。
  2. 循环引用:如果你的对象图中有循环引用(A 包含 B,B 又包含 A),序列化时可能会栈溢出或陷入死循环,需要小心设计对象结构,或在某些框架中配置处理循环引用的策略。
  3. 版本兼容性:如果服务端的 User 类发生了结构变化(比如新增了一个字段),而客户端没有更新,可能会导致反序列化失败,在设计 API 时应考虑向后兼容性。
  4. 安全性:在网络上传输对象数据时,特别是敏感信息,务必使用 HTTPS 加密传输,以防止数据被窃听或篡改。

希望这个详细的解释能帮助你全面理解 Java WebService 中的“对象”概念及其交互方式。

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