Introduction to JAX-WS – JAX-WS简介

最后修改: 2017年 4月 26日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Java API for XML Web Services (JAX-WS) is a standardized API for creating and consuming SOAP (Simple Object Access Protocol) web services.

Java API for XML Web Services(JAX-WS)是一个标准化的API,用于创建和消费SOAP(简单对象访问协议)Web服务。

In this article, we’ll create a SOAP web service and connect to it using JAX-WS.

在这篇文章中,我们将创建一个SOAP网络服务并使用JAX-WS连接到它。

2. SOAP

2.SOAP

SOAP is an XML specification for sending messages over a network. SOAP messages are independent of any operating system and can use a variety of communication protocols including HTTP and SMTP.

SOAP是一种用于通过网络发送消息的XML规范。SOAP消息独立于任何操作系统,可以使用各种通信协议,包括HTTP和SMTP.

SOAP is XML heavy, hence best used with tools/frameworks. JAX-WS is a framework that simplifies using SOAP. It is part of standard Java.

SOAP是重度XML,因此最好与工具/框架一起使用。JAX-WS是一个简化了SOAP使用的框架。它是标准Java的一部分。

3. Top-Down vs. Bottom-Up

3.自上而下与自下而上

There are two ways of building SOAP web services. We can go with a top-down approach or a bottom-up approach.

有两种构建SOAP网络服务的方法。我们可以采用自上而下的方式,也可以采用自下而上的方式。

In a top-down (contract-first) approach, a WSDL document is created, and the necessary Java classes are generated from the WSDL. In a bottom-up (contract-last) approach, the Java classes are written, and the WSDL is generated from the Java classes.

在自上而下(契约优先)的方法中,WSDL 文档被创建,而必要的 Java 类则从 WSDL 中生成。在自下而上(合约最后)的方法中,Java 类被编写,而 WSDL 是由Java 类生成的。

Writing a WSDL file can be quite difficult depending on how complex your web service is. This makes the bottom-up approach an easier option. On the other hand, since your WSDL is generated from the Java classes, any change in code might cause a change in the WSDL. This is not the case for the top-down approach.

编写WSDL文件可能相当困难,这取决于你的网络服务有多复杂。这使得自下而上的方法成为更容易的选择。另一方面,由于你的WSDL是从Java类中生成的,代码中的任何变化都可能导致WSDL的变化。而自上而下的方法则不会出现这种情况。

In this article, we’ll take a look at both approaches.

在这篇文章中,我们将看一下这两种方法。

4. Web Services Definition Language (WSDL)

4.网络服务定义语言(WSDL)

WSDL is a contract definition of the available services. It is a specification of input/output messages, and how to invoke the web service. It is language neutral and is defined in XML.

WSDL是对可用服务的合同定义。它是输入/输出消息的规范,以及如何调用网络服务。它是语言中立的,并且是用XML定义的。

Let’s look at the major elements of a WSDL document.

我们来看看WSDL文档的主要元素。

4.1. Definitions

4.1.定义

The definitions element is the root element of all WSDL documents. It defines the name, the namespace, etc. of the service and, as you can see, can be quite spacious:

definitions元素是所有WSDL文档的根元素。它定义了服务的名称、命名空间等,正如你所看到的,它可以很宽敞。

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:tns="http://jaxws.baeldung.com/" 
  xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
  xmlns:wsp="http://www.w3.org/ns/ws-policy" 
  xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  targetNamespace="http://jaxws.baeldung.com/" 
  name="EmployeeService">
  ...
</definitions>

4.2. Types

4.2.类型

The types element defines the data types used by the web service. WSDL uses XSD (XML Schema Definition) as the type system which helps with interoperability:

types元素定义了网络服务所使用的数据类型。WSDL使用XSD(XML Schema Definition)作为类型系统,这有助于实现互操作性。

<definitions ...>
    ...
    <types>
        <xsd:schema>
            <xsd:import namespace="http://jaxws.baeldung.com/" 
              schemaLocation = "http://localhost:8080/employeeservice?xsd=1" />
        </xsd:schema>
    </types>
    ...
</definitions>

4.3. Messages

4.3.信息

The message element provides an abstract definition of the data being transmitted. Each message element describes the input or output of a service method and the possible exceptions:

message元素提供了被传输数据的抽象定义。每个message元素都描述了一个服务方法的输入或输出以及可能的例外情况。

<definitions ...>
    ...
    <message name="getEmployee">
        <part name="parameters" element="tns:getEmployee" />
    </message>
    <message name="getEmployeeResponse">
        <part name="parameters" element="tns:getEmployeeResponse" />
    </message>
    <message name="EmployeeNotFound">
        <part name="fault" element="tns:EmployeeNotFound" />
    </message>
    ...
</definitions>

4.4. Operations and Port Types

4.4.操作和端口类型

The portType element describes each operation that can be performed and all the message elements involved. For example, the getEmployee operation specifies the request input, output and possible fault exception thrown by the web service operation:

portType元素描述了可执行的每个操作以及所有涉及的message元素。例如,getEmployee操作指定了请求输入输出和Web服务操作可能抛出的故障异常。

<definitions ...>
    ...
    <portType name="EmployeeService">
        <operation name="getEmployee">
            <input 
              wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeRequest" 
              message="tns:getEmployee" />
            <output 
              wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeResponse" 
              message="tns:getEmployeeResponse" />
            <fault message="tns:EmployeeNotFound" name="EmployeeNotFound" 
              wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployee/Fault/EmployeeNotFound" />
        </operation>
    ....
    </portType>
    ...
</definitions>

4.5. Bindings

4.5.绑定

The binding element provides protocol and data format details for each portType:

binding元素为每个portType提供协议和数据格式细节。

<definitions ...>
    ...
    <binding name="EmployeeServiceImplPortBinding" 
      type="tns:EmployeeService">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" 
          style="document" />
        <operation name="getEmployee">
            <soap:operation soapAction="" />
            <input>
                <soap:body use="literal" />
            </input>
            <output>
                <soap:body use="literal" />
            </output>
            <fault name="EmployeeNotFound">
                <soap:fault name="EmployeeNotFound" use="literal" />
            </fault>
        </operation>
        ...
    </binding>
    ...
</definitions>

4.6. Services and Ports

4.6.服务和港口

The service element defines the ports supported by the web service. The port element in service defines the name, binding and the address of the service:

service元素定义了Web服务所支持的端口。service中的port元素定义了服务的namebindingaddress

<definitions ...>
    ...
    <service name="EmployeeService">
        <port name="EmployeeServiceImplPort" 
          binding="tns:EmployeeServiceImplPortBinding">
            <soap:address 
              location="http://localhost:8080/employeeservice" />
        </port>
    </service>
    ...
</definitions>

5. Top-Down (Contract-First) Approach

5.自上而下(合同优先)的方法

Let’s start with a top-down approach by creating a WSDL file employeeservicetopdown.wsdl. For the sake of simplicity, it has only one method:

让我们从自上而下的方法开始,创建一个 WSDL 文件 employeeservicetopdown.wsdl。为了简单起见,它只有一个方法。

<?xml version="1.0" encoding="UTF-8"?>
<definitions 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://topdown.server.jaxws.baeldung.com/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  targetNamespace="http://topdown.server.jaxws.baeldung.com/"
  qname="EmployeeServiceTopDown">
    <types>
        <xsd:schema 
          targetNamespace="http://topdown.server.jaxws.baeldung.com/">
            <xsd:element name="countEmployeesResponse" type="xsd:int"/>
        </xsd:schema>
    </types>

    <message name="countEmployees">
    </message>
    <message name="countEmployeesResponse">
        <part name="parameters" element="tns:countEmployeesResponse"/>
    </message>
    <portType name="EmployeeServiceTopDown">
        <operation name="countEmployees">
            <input message="tns:countEmployees"/>
            <output message="tns:countEmployeesResponse"/>
        </operation>
    </portType>
    <binding name="EmployeeServiceTopDownSOAP" 
      type="tns:EmployeeServiceTopDown">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" 
          style="document"/>
        <operation name="countEmployees">
            <soap:operation 
              soapAction="http://topdown.server.jaxws.baeldung.com/
              EmployeeServiceTopDown/countEmployees"/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
    </binding>
    <service name="EmployeeServiceTopDown">
        <port name="EmployeeServiceTopDownSOAP" 
          binding="tns:EmployeeServiceTopDownSOAP">
            <soap:address 
              location="http://localhost:8080/employeeservicetopdown"/>
        </port>
    </service>
</definitions>

5.1. Generating Web Service Source Files from WSDL

5.1.从 WSDL 生成 Web 服务源文件

There are several ways to generate web service source files from a WSDL document.

有几种方法可以从WSDL文档中生成Web服务源文件。

One way is to use the wsimport tool which is part of JDK (at $JAVA_HOME/bin) till JDK 8.

一种方法是使用wsimport工具,它是JDK的一部分(在$JAVA_HOME/bin)直到JDK 8。

From the command prompt:

在命令提示符下。

wsimport -s . -p com.baeldung.jaxws.server.topdown employeeservicetopdown.wsdl

Command line options used: -p specifies the target package. -s specifies where to put the generated source files.

使用的命令行选项。-p指定目标包。-s指定将生成的源文件放在哪里。

For later JDK versions, we can use jaxws-maven-plugin by MojoHaus as described here.

对于后来的JDK版本,我们可以使用MojoHaus的jaxws-maven-plugin,如这里所述。

Alternatively, org.jvnet.jaxb2‘s maven-jaxb2-plugin can come in handy as detailed in Invoking a SOAP Web Service in Spring.

另外,org.jvnet.jaxb2maven-jaxb2-plugin可以派上用场,详见在Spring中调用SOAP Web Service

The generated files:

生成的文件。

  • EmployeeServiceTopDown.java – is the service endpoint interface (SEI) that contains method definitions
  • ObjectFactory.java – contains factory methods to create instances of schema derived classes programmatically
  • EmployeeServiceTopDown_Service.java – is the service provider class that can be used by a JAX-WS client

5.2. Web Service Endpoint Interface

5.2.网络服务端点接口

The wsimport tool has generated the web service endpoint interface EmployeeServiceTopDown. It declares the web service methods:

wsimport工具已经生成了网络服务端点接口 EmployeeServiceTopDown。它声明了网络服务方法。

@WebService(
  name = "EmployeeServiceTopDown", 
  targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class
})
public interface EmployeeServiceTopDown {
    @WebMethod(
      action = "http://topdown.server.jaxws.baeldung.com/"
      + "EmployeeServiceTopDown/countEmployees")
    @WebResult(
      name = "countEmployeesResponse", 
      targetNamespace = "http://topdown.server.jaxws.baeldung.com/", 
      partName = "parameters")
    public int countEmployees();
}

5.3. Web Service Implementation

5.3.网络服务的实施

The wsimport tool has created the structure of the web service. We have to create the implementation of the web service:

wsimport工具已经创建了网络服务的结构。我们必须创建网络服务的实现。

@WebService(
  name = "EmployeeServiceTopDown", 
  endpointInterface = "com.baeldung.jaxws.server.topdown.EmployeeServiceTopDown",
  targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
public class EmployeeServiceTopDownImpl 
  implements EmployeeServiceTopDown {
 
    @Inject 
    private EmployeeRepository employeeRepositoryImpl;
 
    @WebMethod
    public int countEmployees() {
        return employeeRepositoryImpl.count();
    }
}

6. Bottom-Up (Contract-Last) Approach

6.自下而上(合同-最后)的方法

In a bottom-up approach, we have to create both the endpoint interface and the implementation classes. The WSDL is generated from the classes when the web service is published.

在自下而上的方法中,我们必须同时创建端点接口和实现类。当网络服务被发布时,WSDL由这些类生成。

Let’s create a web service that will perform simple CRUD operations on Employee data.

让我们创建一个Web服务,它将对Employee数据执行简单的CRUD操作。

6.1. The Model Class

6.1.模型类

The Employee model class:

Employee模型类。

public class Employee {
    private int id;
    private String firstName;

    // standard getters and setters
}

6.2. Web Service Endpoint Interface

6.2.网络服务端点接口

The web service endpoint interface which declares the web service methods:

网络服务端点接口,它声明了网络服务方法。

@WebService
public interface EmployeeService {
    @WebMethod
    Employee getEmployee(int id);

    @WebMethod
    Employee updateEmployee(int id, String name);

    @WebMethod
    boolean deleteEmployee(int id);

    @WebMethod
    Employee addEmployee(int id, String name);

    // ...
}

This interface defines an abstract contract for the web service. The annotations used:

这个接口定义了网络服务的抽象契约。使用的注解。

  • @WebService denotes that it is a web service interface
  • @WebMethod is used to customize a web service operation
  • @WebResult is used to customize name of the XML element that represents the return value

6.3. Web Service Implementation

6.3.网络服务的实施

The implementation class of the web service endpoint interface:

网络服务端点接口的实现类。

@WebService(endpointInterface = "com.baeldung.jaxws.EmployeeService")
public class EmployeeServiceImpl implements EmployeeService {
 
    @Inject 
    private EmployeeRepository employeeRepositoryImpl;

    @WebMethod
    public Employee getEmployee(int id) {
        return employeeRepositoryImpl.getEmployee(id);
    }

    @WebMethod
    public Employee updateEmployee(int id, String name) {
        return employeeRepositoryImpl.updateEmployee(id, name);
    }

    @WebMethod
    public boolean deleteEmployee(int id) {
        return employeeRepositoryImpl.deleteEmployee(id);
    }

    @WebMethod
    public Employee addEmployee(int id, String name) {
        return employeeRepositoryImpl.addEmployee(id, name);
    }

    // ...
}

7. Publishing the Web Service Endpoints

7.发布网络服务端点

To publish the web services (top-down and bottom-up), we need to pass an address and an instance of the web service implementation to the publish() method of the javax.xml.ws.Endpoint class:

为了发布Web服务(自上而下和自下而上),我们需要向javax.xml.ws.Endpoint类的publish()方法传递一个地址和一个Web服务实现的实例。

public class EmployeeServicePublisher {
    public static void main(String[] args) {
        Endpoint.publish(
          "http://localhost:8080/employeeservicetopdown", 
           new EmployeeServiceTopDownImpl());

        Endpoint.publish("http://localhost:8080/employeeservice", 
          new EmployeeServiceImpl());
    }
}

We can now run EmployeeServicePublisher to start the web service. To make use of CDI features, the web services can be deployed as WAR file to application servers like WildFly or GlassFish.

我们现在可以运行EmployeeServicePublisher来启动Web服务。为了利用CDI功能,可以将Web服务作为WAR文件部署到WildFly或GlassFish等应用服务器上。

8. Remote Web Service Client

8.远程网络服务客户端

Let’s now create a JAX-WS client to connect to the EmployeeService web service remotely.

现在让我们创建一个JAX-WS客户端来远程连接到EmployeeService网络服务。

8.1. Generating Client Artifacts

8.1.生成客户端工件

To generate JAX-WS client artifacts, we can once again use the wsimport tool:

为了生成JAX-WS客户端工件,我们可以再次使用wsimport工具。

wsimport -keep -p com.baeldung.jaxws.client http://localhost:8080/employeeservice?wsdl

The generated EmployeeService_Service class encapsulates the logic to get the server port using URL and QName.

生成的EmployeeService_Service类封装了使用URLQName获得服务器端口的逻辑。

8.2. Connecting to the Web Service

8.2.连接到网络服务

The web service client uses the generated EmployeeService_Service to connect to the server and make web service calls remotely:

网络服务客户端使用生成的EmployeeService_Service连接到服务器并远程进行网络服务调用。

public class EmployeeServiceClient {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://localhost:8080/employeeservice?wsdl");

        EmployeeService_Service employeeService_Service 
          = new EmployeeService_Service(url);
        EmployeeService employeeServiceProxy 
          = employeeService_Service.getEmployeeServiceImplPort();

        List<Employee> allEmployees 
          = employeeServiceProxy.getAllEmployees();
    }
}

9. Conclusion

9.结论

This article is a quick introduction to SOAP Web services using JAX-WS.

本文是对使用JAX-WS的SOAP Web服务的快速介绍

We have used both the bottom-up and top-down approaches to creating SOAP Web services using the JAX-WS API. We have also written a JAX-WS client that can remotely connect to the server and make web service calls.

我们使用了自下而上和自上而下的方法来创建使用JAX-WS API的SOAP Web服务。我们还编写了一个JAX-WS客户端,可以远程连接到服务器并进行Web服务调用。

The complete source code is available over on GitHub.

完整的源代码可在GitHub上获得