Java SOAP Web服务开发指南:Eclipse实例详解

这是文章《用Eclipse示例在Java中实现SOAP网络服务》的第1部分(共3部分)。

在Java中,可以以多种方式开发SOAP网络服务。在上一篇教程中,我们学习了JAX-WS SOAP网络服务,今天我们将学习如何使用Eclipse创建SOAP网络服务以及其客户端程序。在这里,我们不使用JAX-WS,而是使用集成在Eclipse中的Apache Axis,它提供了一种快速简便的方式将应用程序转换为Java网络服务,并创建用于测试目的的客户端存根和测试JSP页面。

在Java中的SOAP Web服务

我正在使用Eclipse Mars Release (4.5.0)进行本教程,但我认为这些步骤也适用于较旧版本的Eclipse。另外,请确保您在Eclipse中添加了Apache Tomcat或任何其他servlet容器作为服务器。现在让我们开始我们的Eclipse网络服务实现。

SOAP网络服务示例

让我们用Eclipse开始我们的SOAP web服务示例。首先,我们将在Eclipse中创建一个简单的动态Web项目,其中包含我们应用程序的业务逻辑。点击上面的下一步按钮,您将获得下一个页面来提供您的Web项目名称和目标运行时。请注意,我正在使用Apache Tomcat 8,您也可以使用其他标准的servlet容器。点击下一步,您将被要求提供”Context Root”和内容目录位置。您可以将它们保持默认设置。点击完成,Eclipse将为您创建项目骨架。让我们开始我们的业务逻辑。因此,对于我们的示例,我们希望发布一个可以用于添加/删除/获取对象的Web服务。因此,第一步是创建一个模型bean。

package com.Olivia.jaxws.beans;

import java.io.Serializable;

public class Person implements Serializable{

	private static final long serialVersionUID = -5577579081118070434L;
	
	private String name;
	private int age;
	private int id;

	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;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	
	@Override
	public String toString(){
		return id+"::"+name+"::"+age;
	}

}

请注意上面是一个简单的Java bean,我们实现了Serializable接口,因为我们将在网络上传输它。我们还提供了toString方法的实现,当我们在客户端打印这个对象时会用到。下一步是创建服务类,我们将有一个名为PersonService的接口以及它的简单实现类PersonServiceImpl。

package com.Olivia.jaxws.service;

import com.Olivia.jaxws.beans.Person;

public interface PersonService {

	public boolean addPerson(Person p);
	
	public boolean deletePerson(int id);
	
	public Person getPerson(int id);
	
	public Person[] getAllPersons();
}

下面是实现服务类,我们使用Map将Person对象存储为数据源。在实际的编程中,我们希望将它们保存到数据库表中。

package com.Olivia.jaxws.service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.Olivia.jaxws.beans.Person;

public class PersonServiceImpl implements PersonService {

	private static Map<Integer,Person> persons = new HashMap<Integer,Person>();
	
	@Override
	public boolean addPerson(Person p) {
		if(persons.get(p.getId()) != null) return false;
		persons.put(p.getId(), p);
		return true;
	}

	@Override
	public boolean deletePerson(int id) {
		if(persons.get(id) == null) return false;
		persons.remove(id);
		return true;
	}

	@Override
	public Person getPerson(int id) {
		return persons.get(id);
	}

	@Override
	public Person[] getAllPersons() {
		Set<Integer> ids = persons.keySet();
		Person[] p = new Person[ids.size()];
		int i=0;
		for(Integer id : ids){
			p[i] = persons.get(id);
			i++;
		}
		return p;
	}

}

这就是我们的业务逻辑,因为我们将在 web 服务中使用它们,所以在这里创建网页没有意义。请注意,在上述代码中我们没有引用任何类型的 web 服务类。

在Eclipse中使用Java的SOAP Web服务

一旦我们的业务逻辑准备就绪,下一步是使用Eclipse从中创建一个Web服务应用程序。创建一个新项目并选择Web服务向导。点击”下一步”按钮,您将获得一个页面,需要提供Web服务及其客户端的详细信息。这是创建Web服务最重要的页面。确保将”Web服务类型”选择为”自下而上的Java Bean Web服务”,因为我们正在采用自下而上的方法实现。创建Web服务有两种方法:

  1. 合同先或自下而上方法:在这种方法中,我们首先创建实现,然后从中生成WSDL文件。我们的实现符合这一类别。
  2. 合同先或自上而下方法:在这种方法中,我们首先创建Web服务合同,即WSDL文件,然后为其创建实现。

在服务实现中,提供实现类PersonServiceImpl的完整分类路径。确保将滑块移动到服务和客户端类型左侧,这样它就能生成客户端程序和UI以测试我们的Web服务。检查Web服务实现中的配置,您应该提供正确的服务器运行时、Web服务运行时和服务项目详细信息。通常它们会自动填充,您不需要在此处进行任何更改。对于客户端配置,您可以根据需要提供客户端项目名称。我将其设置为默认值SOAPExampleClient。如果您单击Web服务运行时的链接,您将获得如下图所示的不同选项。然而,我将其保留为默认选项。单击”下一步”按钮,然后您将能够选择要作为Web服务公开的方法。您还可以选择Web服务样式,可以是文档型或字面型。您可以更改WSDL文档名称,但最好将其与实现类名称保持一致,以避免以后造成混淆。单击”下一步”按钮,您将获得服务器启动页面,单击”启动服务器”按钮,然后下一步按钮将可用。单击”下一步”按钮,您将获得启动”Web服务资源浏览器”的页面。单击”启动”按钮,它将在浏览器中打开一个新窗口,您可以在其中测试Web服务,然后再进行客户端应用程序部分。对于我们的项目,它看起来如下图所示。我们可以在这里进行一些基本测试,但对于我们的简单应用程序,我准备继续创建客户端应用程序。单击Eclipse Web服务弹出窗口中的”下一步”按钮,您将获得为客户端应用程序选择源文件夹的页面。单击”下一步”按钮,您将获得不同的选项以选择作为测试工具。我将使用JAX-RPC JSP,以便客户端应用程序将生成一个我们可以使用的JSP页面。请注意添加的getEndpoint()和setEndpoint(String)方法,我们可以使用它们来获取Web服务的端点URL,并在将服务器移动到其他端点URL时将其设置为其他URL。单击”完成”按钮,Eclipse将在您的工作区创建客户端项目,并启动客户端测试JSP页面,如下图所示。您可以复制URL并在任何您喜欢的浏览器中打开它。让我们测试一些我们已公开的服务并查看输出结果。

Eclipse SOAP Web 服务测试

  • addPerson方法
  • getPerson方法
  • getAllPersons方法

    请注意,Person详细信息没有在结果部分打印出来,这是因为它是自动生成的代码,我们需要对其进行一些重构以获得所需的输出。在客户端项目中打开Result.jsp文件,您将看到它使用switch case来生成结果输出。对于getAllPersons()方法,在我的例子中是case 42。请注意,在您的情况下可能完全不同。我只是修改了case 42的代码,如下所示。

    case 42:
        gotMethod = true;
        com.Olivia.jaxws.beans.Person[] getAllPersons42mtemp = samplePersonServiceImplProxyid.getAllPersons();
        if(getAllPersons42mtemp == null){
            %>
            <%=getAllPersons42mtemp %>
            <%
        }else{
            String tempreturnp43 = null;
            if(getAllPersons42mtemp != null){
                java.util.List listreturnp43= java.util.Arrays.asList(getAllPersons42mtemp);
                //tempreturnp43 = listreturnp43.toString();
                for(com.Olivia.jaxws.beans.Person p : listreturnp43){
                    int id = p.getId();
                    int age = p.getAge();
                    String name=p.getName();
                    %>
                    <%=id%>::<%=name %>::<%=age %>
                    <%
                }
            }
        }
        break;

    之后,我们得到如下输出,请注意Eclipse在这里进行热部署,所以我不必重新部署我的应用程序。

看起来我们的网络服务和客户端应用程序正常工作。请花些时间查看Eclipse生成的客户端存根代码,以便更好地理解。

SOAP网络服务WSDL和配置

最后,您会注意到在Web服务项目中生成了以下WSDL文件。PersonServiceImpl.wsdl代码:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="https://service.jaxws.scdev.com" xmlns:apachesoap="https://xml.apache.org/xml-soap" xmlns:impl="https://service.jaxws.scdev.com" xmlns:intf="https://service.jaxws.scdev.com" xmlns:tns1="https://beans.jaxws.scdev.com" xmlns:wsdl="https://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="https://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="https://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)-->
 <wsdl:types>
  <schema elementFormDefault="qualified" targetNamespace="https://service.jaxws.scdev.com" xmlns="https://www.w3.org/2001/XMLSchema">
   <import namespace="https://beans.jaxws.scdev.com"/>
   <element name="addPerson">
    <complexType>
     <sequence>
      <element name="p" type="tns1:Person"/>
     </sequence>
    </complexType>
   </element>
   <element name="addPersonResponse">
    <complexType>
     <sequence>
      <element name="addPersonReturn" type="xsd:boolean"/>
     </sequence>
    </complexType>
   </element>
   <element name="deletePerson">
    <complexType>
     <sequence>
      <element name="id" type="xsd:int"/>
     </sequence>
    </complexType>
   </element>
   <element name="deletePersonResponse">
    <complexType>
     <sequence>
      <element name="deletePersonReturn" type="xsd:boolean"/>
     </sequence>
    </complexType>
   </element>
   <element name="getPerson">
    <complexType>
     <sequence>
      <element name="id" type="xsd:int"/>
     </sequence>
    </complexType>
   </element>
   <element name="getPersonResponse">
    <complexType>
     <sequence>
      <element name="getPersonReturn" type="tns1:Person"/>
     </sequence>
    </complexType>
   </element>
   <element name="getAllPersons">
    <complexType/>
   </element>
   <element name="getAllPersonsResponse">
    <complexType>
     <sequence>
      <element maxOccurs="unbounded" name="getAllPersonsReturn" type="tns1:Person"/>
     </sequence>
    </complexType>
   </element>
  </schema>
  <schema elementFormDefault="qualified" targetNamespace="https://beans.jaxws.scdev.com" xmlns="https://www.w3.org/2001/XMLSchema">
   <complexType name="Person">
    <sequence>
     <element name="age" type="xsd:int"/>
     <element name="id" type="xsd:int"/>
     <element name="name" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
  </schema>
 </wsdl:types>

   <wsdl:message name="addPersonResponse">

      <wsdl:part element="impl:addPersonResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="getAllPersonsResponse">

      <wsdl:part element="impl:getAllPersonsResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="deletePersonResponse">

      <wsdl:part element="impl:deletePersonResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="addPersonRequest">

      <wsdl:part element="impl:addPerson" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="getPersonResponse">

      <wsdl:part element="impl:getPersonResponse" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="getPersonRequest">

      <wsdl:part element="impl:getPerson" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="deletePersonRequest">

      <wsdl:part element="impl:deletePerson" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:message name="getAllPersonsRequest">

      <wsdl:part element="impl:getAllPersons" name="parameters">

      </wsdl:part>

   </wsdl:message>

   <wsdl:portType name="PersonServiceImpl">

      <wsdl:operation name="addPerson">

         <wsdl:input message="impl:addPersonRequest" name="addPersonRequest">

       </wsdl:input>

         <wsdl:output message="impl:addPersonResponse" name="addPersonResponse">

       </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="deletePerson">

         <wsdl:input message="impl:deletePersonRequest" name="deletePersonRequest">

       </wsdl:input>

         <wsdl:output message="impl:deletePersonResponse" name="deletePersonResponse">

       </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="getPerson">

         <wsdl:input message="impl:getPersonRequest" name="getPersonRequest">

       </wsdl:input>

         <wsdl:output message="impl:getPersonResponse" name="getPersonResponse">

       </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="getAllPersons">

         <wsdl:input message="impl:getAllPersonsRequest" name="getAllPersonsRequest">

       </wsdl:input>

         <wsdl:output message="impl:getAllPersonsResponse" name="getAllPersonsResponse">

       </wsdl:output>

      </wsdl:operation>

   </wsdl:portType>

   <wsdl:binding name="PersonServiceImplSoapBinding" type="impl:PersonServiceImpl">

      <wsdlsoap:binding style="document" transport="https://schemas.xmlsoap.org/soap/http"/>

      <wsdl:operation name="addPerson">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="addPersonRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="addPersonResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="deletePerson">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="deletePersonRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="deletePersonResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="getPerson">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="getPersonRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="getPersonResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

      <wsdl:operation name="getAllPersons">

         <wsdlsoap:operation soapAction=""/>

         <wsdl:input name="getAllPersonsRequest">

            <wsdlsoap:body use="literal"/>

         </wsdl:input>

         <wsdl:output name="getAllPersonsResponse">

            <wsdlsoap:body use="literal"/>

         </wsdl:output>

      </wsdl:operation>

   </wsdl:binding>

   <wsdl:service name="PersonServiceImplService">

      <wsdl:port binding="impl:PersonServiceImplSoapBinding" name="PersonServiceImpl">

         <wsdlsoap:address location="https://localhost:8080/SOAPExample/services/PersonServiceImpl"/>

      </wsdl:port>

   </wsdl:service>

</wsdl:definitions>

如果您在Eclipse的设计模式下打开它,它将会呈现如下图所示。您也可以通过在浏览器中添加”?wsdl”来访问Web服务的WSDL文件。您还会注意到web.xml被修改为使用Apache Axis作为Web服务的前端控制器。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>SOAPExample</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <display-name>Apache-Axis Servlet</display-name>
    <servlet-name>AxisServlet</servlet-name>
    <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>/servlet/AxisServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>*.jws</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
  <servlet>
    <display-name>Axis Admin Servlet</display-name>
    <servlet-name>AdminServlet</servlet-name>
    <servlet-class>org.apache.axis.transport.http.AdminServlet</servlet-class>
    <load-on-startup>100</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>AdminServlet</servlet-name>
    <url-pattern>/servlet/AdminServlet</url-pattern>
  </servlet-mapping>
</web-app>

下图显示了具有所有自动生成的存根和JSP页面来测试Web服务的Web服务和客户端项目。就使用Eclipse实现Java SOAP Web服务而言,这就是全部内容。正如您所看到的,Eclipse自动完成了所有困难的部分,我们只需要专注于为我们的Web服务编写业务逻辑。

bannerAds