用Eclipse示例在Java中实现SOAP网服务
在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 Notice that Person details are not printed in the results section, this is because it’s auto generated code and we need to refactor it a little to get the desired output. Open Result.jsp in the client project and you will see it’s using switch case to generate the result output. For getAllPersons() method, it was case 42 in my case. Note that it could be totally different in your case. I just changed the code for case 42 as shown below.
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;After that we get below output, note that Eclipse is doing hot deployment here, so I didn’t had to redeploy my application.
看起来我们的网络服务和客户端应用程序正常工作,请花些时间查看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页面来测试网络服务的网络服务和客户端项目。就SOAP Web服务在使用Eclipse的Java示例而言,这就是全部内容。正如您所看到的,Eclipse自动完成了所有困难的部分,我们只需要专注于为我们的Web服务编写业务逻辑。