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服务有两种方法:
- 合同先或自下而上方法:在这种方法中,我们首先创建实现,然后从中生成WSDL文件。我们的实现符合这一类别。
- 合同先或自上而下方法:在这种方法中,我们首先创建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服务编写业务逻辑。