- 浏览: 159806 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
fengwuqing40:
zxh277100963 写道有个bug String输入数字 ...
pinyin4j 中文转成拼音(支持多音字输出) -
pimkle:
楼主说的很好 评论补充的也好 像是解决了多音字的问题 可是还需 ...
pinyin4j 中文转成拼音(支持多音字输出) -
yangjianzhouctgu:
请问org.rut.util.algorithm.SortUt ...
java排序归总 -
zxh277100963:
有个bug String输入数字 报错
修改一下
...
pinyin4j 中文转成拼音(支持多音字输出) -
gejialun88:
java环境下使用jQuery进行JSON数据传送的交互过程
一、 Web Service的简介
1、 什么是Web Service
Web services是建立可互操作的分布式应用程序的新平台。
Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。
Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,Web service平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。
基础的 Web Services 平台是 XML + HTTP。
HTTP 协议是最常用的因特网协议。
XML 提供了一种可用于不同的平台和编程语言之间的语言。
Web services 平台是简单的可共同操作的消息收发框架。它仍然缺少许多诸如安全和路由等重要的特性。但是,一旦 SOAP 变得更加高级,这些事项就会得到解决。
Web services 有望使应用程序更加容易通信。
★ Web services 把 Web 应用程序提升到了另外一个层面
通过使用 Web services,您的应用程序可向全世界发布功能或消息。
Web services 使用 XML 来编解码数据,并使用 SOAP 借由开放的协议来传输数据。
通过 Web services,您的会计部门的 Win 2k 服务器可与 IT 供应商的 UNIX 服务器进行连接。
★ Web services 有两种类型的应用
可重复使用的应用程序组件
有一些功能是不同的应用程序常常会用到的。那么为什么要周而复始地开发它们呢?
Web services 可以把应用程序组件作为服务来提供,比如汇率转换、天气预报或者甚至是语言翻译等等。
比较理想的情况是,每种应用程序组件只有一个最优秀的版本,这样任何人都可以在其应用程序中使用它。
连接现有的软件
通过为不同的应用程序提供一种链接其数据的途径,Web services有助于解决协同工作的问题。
通过使用 Web services,您可以在不同的应用程序与平台之间来交换数据。
★ Web Services 拥有两种基本的元素。
它们是:SOAP及WSDL
(1)什么是 SOAP?
SOAP 指简易对象访问协议
SOAP 是一种通信协议
SOAP 用于应用程序之间的通信
SOAP 是一种用于发送消息的格式
SOAP 被设计用来通过因特网进行通信
SOAP 独立于平台
SOAP 独立于语言
SOAP 基于 XML
SOAP 很简单并可扩展
SOAP 允许您绕过防火墙
SOAP 将作为 W3C 标准来发展
(2)什么是 WSDL?
WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言。
WSDL 指网络服务描述语言
WSDL 使用 XML 编写
WSDL 是一种 XML 文档
WSDL 用于描述网络服务
WSDL 也可用于定位网络服务
WSDL 还不是 W3C 标准
2、 什么是JWS
JWS(Java Web Service)是Java应用平台上专门用于开发Web服务系统及面向服务系统的产品,它的最新版本是2.0,Java EE 5和Java SE 6都对JWS 2.0提供支持。
在JWS 2.0,Java定义了一系列新的标准,JMS本身也包含了一些工具,如JAX-WS 2.0,JAXB 2.0,JAXP 1.4,SAAJ 1.3以及WS-Metadata等。
面向服务的系统往往由多个具有不同的子功能的独立组件构成,通过他们之间良好的相互协作,可以实现复杂的需求。面向服务系统的这个特点,要求独立组建之间有公共的接口,这些用于交换数据的公共接口有良好的定义。由于要实现组件之间的数据通信,这些具有良好定义的接口就必须要被别的组件识别并正确理解,才能实现协作。
在定义了公共的接口后,还存在具体的数据交换问题,即双方需要遵循一个共同的数据交换标准,这个数据交换标准称为协议。要在独立的组件之间进行通信,需要一系列标准来严格规定数据通信的格式和规则。
Web Service的出现解决了上述问题,利用WSDL定义统一的接口格式,用SOAP消息统一输入/输出参数的统一格式。SOAP消息可以由多种途径传递,比如,通过HTTP,SMTP及JMS协议传递。以HTTP为例,在服务使用端,WSDL的接口定义可以通过HTTP-GET请求获取,而SOAP应答消息及回复消息的传输可以通过HTTP-POST请求来实现。这样,基于WSDL和SOAP消息机制就可以满足面向服务应用系统开发的需求。
Web Service平台架构主要由三部分构成:序列化及反序列化子系统、调用子系统及发布子系统。这三个子系统并不受具体语言的限制,也不受平台和框架的限制,无论使用Java语言还是.NET语言,无论使用Axis平台还是JWS来开发web服务,都会涉及这三个最基本的功能模块。
(1)序列化及反序列化
在JMS中将一个Java对象转化为一个XML元素的过程,称为序列化。反之将一个XML元素转化为相应的Java
对象的过程,称为反序列化。序列化和反序列化的过程要依赖于Java类和XML-Scheme之间的映射关系,JWS有独立
的序列化和反序列化子系统用来负责完成这些映射及转化。
在web服务的客户端,序列化过程将参数转化为xml结点,进而封装成Soap请求消息,发送至服务器端的web服务端点。获得返回值时,反序列化过程启动,它将返回值从SOAP消息中指定的xml结点中取出,然后将它转化为客户端相对应的Java对象。
转化规则的定义在JWS中是通过JAXB的注释来完成的。新版的JAXB简化了绑定规则的描述,它允许直接将规则以注解的形式写入Java类。
例如:
@Entity
@Name("hotel")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlType(name="", propOrder = {
"id",
"img",
"name",
"address",
"city",
"state",
"zip",
"country",
"price",
"ipAddress"
})
@XmlRootElement(name="Hotel")
public class Hotel implements Serializable
{
private Long id;
private String img;
private String name;
private String address;
private String city;
private String state;
private String zip;
private String country;
private BigDecimal price;
private String ipAddress = "192.168.1.112";
@Id @GeneratedValue
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
@Length(max = 50)
@NotNull
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
@Length(max=50) @NotNull
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Length(max=100) @NotNull
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
@Length(max=40) @NotNull
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
@Length(min=4, max=6) @NotNull
public String getZip()
{
return zip;
}
public void setZip(String zip)
{
this.zip = zip;
}
@Length(min=2, max=10) @NotNull
public String getState()
{
return state;
}
public void setState(String state)
{
this.state = state;
}
@Length(min=2, max=40) @NotNull
public String getCountry()
{
return country;
}
public void setCountry(String country)
{
this.country = country;
}
@Column(precision=6, scale=2)
public BigDecimal getPrice()
{
return price;
}
public void setPrice(BigDecimal price)
{
this.price = price;
}
@Transient
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
@Override
public String toString()
{
return "Hotel(" + name + "," + address + "," + city + "," + zip + ")";
}
}
(2)服务调用的过程
在面向服务的分布式系统中,一般将传统的客户服务器框架中的客户端Client称为服务的消费者,而将服务器端称为服务的提供者。
按照现在的web服务标准,一个服务被调用时,在服务的提供端大致的处理过程如下:
①接受并预处理SOAP请求消息,例如效验,处理SOAP消息报文头。
②从消息中获取该消息希望调用的接口和具体操作。
③利用web服务提供的支持,找到具体的实现对象,并调用该对象的接口。这个对象可以由不同的语言实现。JWS支持从WSDL到Java的映射,可以通过WSDL找到与它相对应的Java服务端点实现类。
④使用序列化工具的反序列化过程,将SOAP请求消息中的服务请求参数取出,传递给步骤3中的目标对象的相应函数。
⑤目标Java对象执行相应的操作,将计算的结果以对象形式返回。
⑥使用序列化工具的序列化过程,根据wsdl中的定义,将步骤5中的结果对象序列化成XML元素,并封装到SOAP回复消
息中。
⑦将步骤6中的SOAP回复消息发送回服务调用端。
与之对应的,在服务使用端的调用过程如下:
①首先创建服务端点接口对象SEI(Service Endpoint Interface),在Web服务客户端一般都会有相应的工厂类完成SEI对象的实例化。在JWS中,SEI对象一般是由Java代理来实现的。
②客户端通过SEI调用其中封装的web服务接口。
③利用序列化工具的序列化过程,根据WSDL的定义,将客户端的调用接口的参数转化成XML元素,再将该元素封装在SOAP请求消息里。
④在同步模式下,在SOAP请求消息发出后,客户端会等待SOAP应答消息;异步模式下,客户端顺序执行后续代码,直到通过监听器接收到SOAP请求消息里。
⑤解析从服务器端获得的SOAP应答消息,使用序列化工具中的反序列化过程,将SOAP应答消息中的数据转化成客户端对象,该对象的值就是被调用服务的返回值。
(3)web服务的发布
以JMS为例,web服务发布系统的主要功能
①以URL的形式公开被发布的WEB服务的WSDL文件,并绑定SOAP请求消息和Java目标类。
②发布JAVA目标文件(例如Java Object文件,WAR文件,JAR文件及相关配置文件等)。
③配置序列化和反序列化子系统。
④配置web服务端点监听器和SOAP消息预处理进程。
二、 web service的几种开发及调用方式
(1)用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用。
实例如下(实例中应用的EJB容器为Jboss,所有代码是基于JBoss Seam架构来编写的):
①服务的提供者端<提供服务端的代码>:
服务的提供者端的任务是暴露一个web service以供外部使用,本例的web service是通过JavaEE平台提供的@java.jws.WebService注解来实现的。
以下代码的路径是VSS上 前期调查文件夹下SOA\web service\用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用\tele\book\src\org\jboss\seam\example\booking\ws\impl,用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用文件夹下包括两个文件夹:local,tele。tele文件夹下放服务的提供者端的工程和打好的EAR包。local文件夹下放服务的消费者端的工程和打好的EAR包。
package org.jboss.seam.example.booking.ws.impl;
import static org.jboss.seam.ScopeType.SESSION;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.User;
import org.jboss.seam.example.booking.ws.HotelObject;
@Stateless
/**实例是使用了两个JBoss应用服务器,该代码是服务提供者端的代码,所以使用了@Remote注解,实现远程接口。。*/
@Remote (HotelObject.class)
@WebService
public class HotelObjectImpl implements HotelObject {
@PersistenceContext
private EntityManager em;
public List<Hotel> getHotelObject(String hotelName) {
List<Hotel> results = em.createQuery("select h from Hotel h where h.name like"+ " '%"+hotelName+"%'")
.getResultList();
if(results.size()>0){
return results;
}
return null;
}
public String updateHotelObject(Hotel h){
try{
System.out.println(h);
System.out.println(h.getName());
em.merge(h);
}catch(Exception e ){
e.printStackTrace();
return "error";
}
return "success";
}
}
上面的类继承了一个接口,接口类的路径是:VSS上前期调查文件夹下SOA\web service\用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用\tele\book\src\org\jboss\seam\example\booking\ws。
package org.jboss.seam.example.booking.ws;
import java.util.List;
import org.jboss.seam.example.booking.Hotel;
public interface HotelObject {
public List<Hotel> getHotelObject(String hotelName);
public String updateHotelObject(Hotel h);
}
上面的@WebService注解指名这是一个Web Service。打开Ant文件,执行desploy业务。部署完成后,通过JBoss管理平台查看刚才部署的Web Service,输入http://localhost:8080/jbossws/进入JBoss Web Service的查看界面,可以看到View a list of deployed services链接,单击View a list of deployed services链接后,可以查看已经发布的Web Service的URL地址,单击该地址就可以查看生成的WSDL文。
这就是服务提供端的主要代码,先用注解定义了一个web服务,这个web服务提供了两个方法,这两个方法可以接收从远程传过来的参数。服务的消费着可以通过上面的URL地址访问该服务。
(2)服务的消费者端<使用服务端的代码>
要调用web服务,我们可以通过好多方式,其中的一种方式是通过wsimport工具(在JDK1.6中,Sun已经为用户提供了wsimport工具)生成辅助类来调用web服务。
在VSS上web Service文件夹中有一个叫做jaxws-ri的文件包里面包含了wsimport工具,本例的辅助类就是用它直接生成的。要用wsimport工具生成辅助类,首先要在dos环境下打开wsimport工具所在的目录,比如wsimport工具的本地路径:
Dos下打开wsimport工具所在的路径。
在wsimport路径下输入如下内容:
wsimport.bat -keep -d ../build/classes/client http://192.168.1.106:8080/WsHelloWorld/HelloWorldBean?wsdl
其中../build/classes/client表示生成的辅助类存放的路径,http://192.168.1.106:8080/WsHelloWorld/HelloWorldBean?wsdl表示要调用的web服务的WSDL文地址,其中192.168.1.106表示服务提供端的IP地址。
生成的辅助类如下图所示:
把生成的辅助java类拷贝到我们的工程中
然后实例化一个生成的辅助类的对象,通过该对象调用服务提供者提供的方法<即getHotelObjec()>,去检索符合条件的记录。
该类位于VSS上如下路径下;
SOA\Web Servic\用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用\local\book\src\org\jboss\seam\example\booking
package org.jboss.seam.example.booking;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.ws.impl.Hotel;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImpl;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImplService;
@Stateful
@Name("teledataHotelSearch")
@Scope(ScopeType.SESSION)
@Restrict("#{identity.loggedIn}")
public class TeledateHotelSearchingAction implements TeledateHotelSearching
{
@PersistenceContext
private EntityManager em;
private String searchString;
@DataModel
private List<Hotel> telehotels;
public void find()
{
queryHotels();
}
private void queryHotels() {
/**实例化生成的辅助类的对象,通过该对象调用远程的web service。*/
HotelObjectImplService service;
try
{
service = new HotelObjectImplService();
HotelObjectImpl hotelObjectImpl = service.getHotelObjectImplPort();
List<Hotel> result = hotelObjectImpl.getHotelObject(this.getSearchString());
System.out.println(result.size());
if(result.size()>0){
telehotels = result;
}else{
telehotels =null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getSearchString()
{
return searchString;
}
public void setSearchString(String searchString)
{
this.searchString = searchString;
}
@Remove
public void destroy() {}
@Override
public void cancel() {
// TODO 自动生成的方法存根
}
}
还有一个类是为了保存修改了的服务提供者(即远程的Web Service)返回的Hotel对象,必须调用服务提供者提供的保存Hotel对象的方法<即updateHotelObject ()>。
package org.jboss.seam.example.booking;
import static javax.persistence.PersistenceContextType.EXTENDED;
import java.util.Calendar;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.core.Events;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImpl;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImplService;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;
@Stateful
@Name("saveTeteDataHotel")
@Restrict("#{identity.loggedIn}")
public class SaveTeteDataHotelAction implements SaveTeteDataHotel
{
@Begin
public void seveHotel(Hotel hotel)
{
HotelObjectImplService service;
try
{
service = new HotelObjectImplService();
HotelObjectImpl hotelObjectImpl = service.getHotelObjectImplPort();
String result = hotelObjectImpl.updateHotelObject(this.conversionHotel(hotel));
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
public org.jboss.seam.example.booking.ws.impl.Hotel conversionHotel(Hotel hotel){
org.jboss.seam.example.booking.ws.impl.Hotel h = new org.jboss.seam.example.booking.ws.impl.Hotel();
h.setAddress(hotel.getAddress());
h.setCity(hotel.getCity());
h.setCountry(hotel.getCountry());
h.setId(hotel.getId());
h.setImg(hotel.getImg());
h.setName(hotel.getName());
h.setPrice(hotel.getPrice());
h.setState(hotel.getState());
h.setZip(hotel.getZip());
return h;
}
@End
public void cancel() {}
@Remove
public void destroy() {}
}
以上类中有一点值得注意,就是服务消费者中的Hotel对象不能直接用于保存,必须经过转换,转换成生成的辅助类中的org.jboss.seam.example.booking.ws.impl.Hotel类,才能进行保存,上面的conversionHotel(Hotel hotel)方法就是为了进行该转换。
以上就是该种使用web service的几个重要的点,通过以上各步就可以访问远程发布的web服务,完整的过程请参考Vss上Dome工程。
(2)利用SAAJ协议动态生成SOAP消息访问服务提供者端的web service。
第一种方式是利用wsimpot工具来生成辅助类来实现对服务提供者端的web service的访问,由于生成的辅助类特别多,而且灵活性差。下面我们介绍用SAAJ协议动态生成SOAP消息来访问服务提供者端的web service。
①服务提供者端的代码
该类的在VSS上:
EHR\SOA\SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\ws\impl下
package org.jboss.seam.example.booking.ws.impl;
import static org.jboss.seam.ScopeType.SESSION;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.User;
import org.jboss.seam.example.booking.ws.HotelObject;
@Stateless
@Remote (HotelObject.class)
@WebService(name = "HotelObject", targetNamespace = "http://tower/ehr_DEV")
public class HotelObjectImpl implements HotelObject {
@PersistenceContext
private EntityManager em;
@WebResult(name="Hotel")
public List<Hotel> getHotelObject(String hotelName) {
List<Hotel> results = em.createQuery("select h from Hotel h where h.name like"+ " '%"+hotelName+"%'")
.getResultList();
if(results.size()>0){
return results;
}
return null;
}
public String updateHotelObject(Hotel h){
try{
System.out.println(h);
System.out.println(h.getName());
em.merge(h);
}catch(Exception e ){
e.printStackTrace();
return "error";
}
return "success";
}
}
该web服务提供了两个方法,getHotelObject(String hotelName)方法接收远程的的参数,通过该参数查找符合条件的Hotel对象;updateHotelObject(Hotel h)方法用来保存修改后的对象。
②服务调用者端的代码
该类的在VSS上:
EHR\SOA\ SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\soa\esb\impl下
本例使用了Jboss ESB,其实服务调用端首先发送请求到Jboss ESB服务器上,Jboss ESB服务器上也定义了一些web服务,来接受这些请求,接受到请求消息后,对消息进行进一步的加工或者直接把消息转发给真正的消息提供者端。
下面的代码展示了服务消费端如何通过ESB服务器,去调用服务提供者端提供的服务。
package org.jboss.seam.example.booking.soa.esb.impl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.soap.SOAPMessage;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.commom.collectionbinder.ListHotel;
import org.jboss.seam.example.booking.commom.esb.BuildSoapMessage;
import org.jboss.seam.example.booking.commom.esb.SendSoapMessageToEsb;
import org.jboss.seam.example.booking.commom.esb.impl.BuildSoapMessageImpl;
import org.jboss.seam.example.booking.commom.esb.impl.SendSoapMessageToEsbImpl;
import org.jboss.seam.example.booking.commom.formattransform.TransformMessageFormat;
import org.jboss.seam.example.booking.commom.formattransform.TransformString;
import org.jboss.seam.example.booking.commom.formattransform.impl.TransformMessageFormatImpl;
import org.jboss.seam.example.booking.commom.formattransform.impl.TransformStringImpl;
import org.jboss.seam.example.booking.soa.esb.TeledateHotelSearching;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@Stateful
@Name("teledataHotelSearch")
@Scope(ScopeType.SESSION)
@Restrict("#{identity.loggedIn}")
public class TeledateHotelSearchingImpl implements TeledateHotelSearching
{
@PersistenceContext
private EntityManager em;
private String searchString;
@DataModel
private List<Hotel> telehotels;
public void find()
{
getHotelObject(this.getSearchString());
}
public void getHotelObject(String searchString) {
try{
BuildSoapMessage bsm = new BuildSoapMessageImpl();
SOAPMessage sm = bsm.getMessage("sayGoodbye", "http://webservice_producer/goodbyeworld", searchString);
TransformMessageFormat tmf = new TransformMessageFormatImpl();
String stringSOAPMessage = tmf.transformToString(sm);
SendSoapMessageToEsb smtEsb = new SendSoapMessageToEsbImpl();
Object o = smtEsb.sendMessageToJBRListener("http", "8765", stringSOAPMessage);
System.out.println("wo de ma ya!!!"+o.toString());
TransformString tfs = new TransformStringImpl();
Document doc = tfs.transformStringToDocument(o.toString());
NodeList nodeList = doc.getElementsByTagName("ListHotel");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
if(returnContent.length()>0){
String returnContentAnd = "<ListHotel>"+returnContent+"</ListHotel>";
InputStream inputStream = new ByteArrayInputStream(returnContentAnd.getBytes());
JAXBContext context = JAXBContext.newInstance(ListHotel.class);
try {
Unmarshaller um = context.createUnmarshaller();
ListHotel hl = (ListHotel)um.unmarshal(inputStream);
System.out.println("I'm King!"+hl.getElements());
telehotels = hl.getElements();
} catch (JAXBException e) {
e.printStackTrace();
}
}else{
telehotels = null;
}
}catch(Exception e){
e.printStackTrace();
telehotels = null;
} catch (Throwable e) {
e.printStackTrace();
}
}
public String getSearchString()
{
return searchString;
}
public void setSearchString(String searchString)
{
this.searchString = searchString;
}
@Remove
public void destroy() {}
@Override
public void cancel() {
searchString = "";
telehotels = null;
}
}
在getHotelObject(String searchString)方法中,首先通过BuildSoapMessage类提供的getMessage()方法生成要发送的SOAP消息。(调用的代码如下:)
BuildSoapMessage bsm = new BuildSoapMessageImpl();
SOAPMessage sm = bsm.getMessage("sayGoodbye", "http://webservice_producer/goodbyeworld", searchString);
BuildSoapMessage类及代码如下:
该类的在vss上的路径如下:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\esb\impl
package org.jboss.seam.example.booking.commom.esb.impl;
import java.util.HashMap;
import java.util.Map;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import org.jboss.seam.example.booking.commom.esb.BuildSoapMessage;
public class BuildSoapMessageImpl implements BuildSoapMessage{
public static final SOAPConnection getSOAPConnection(){
SOAPConnectionFactory soapConnFactory;
SOAPConnection connection;
try {
soapConnFactory = SOAPConnectionFactory.newInstance();
connection = soapConnFactory.createConnection();
return connection;
} catch (UnsupportedOperationException e) {
e.printStackTrace();
return null;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public static final SOAPMessage getSOAPMessage(){
MessageFactory messageFactory;
SOAPMessage message;
try {
messageFactory = MessageFactory.newInstance();
message = messageFactory.createMessage();
return message;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public Name getName(String param){
SOAPFactory soapFactory;
try {
soapFactory = SOAPFactory.newInstance();
Name name = soapFactory.createName(param); //"arg0"
return name;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public SOAPElement getBodyElement(SOAPMessage message,String param1,String param2,String param3){
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope;
SOAPBody body;
SOAPElement bodyElement;
try {
envelope = soapPart.getEnvelope();
body = envelope.getBody();
bodyElement = body.addChildElement(envelope.createName(param1,//"sayHello" ,
param1,//"ns1",
param1));//"http://webservice_consumer1/helloworld"));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
return bodyElement;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public SOAPElement addTextNode(SOAPMessage message,String param1,String param2,String param3){
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope;
SOAPBody body;
SOAPElement bodyElement;
try {
envelope = soapPart.getEnvelope();
body = envelope.getBody();
bodyElement = body.addChildElement(envelope.createName(param1,//"sayHello" ,
param1,//"ns1",
param1));//"http://webservice_consumer1/helloworld"));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
return bodyElement;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public SOAPMessage getMessage(String methodName,String targetNamespace,String messageContext) throws SOAPException,Exception{
//传送参数需要创建Name
SOAPFactory soapFactory = SOAPFactory.newInstance();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//获得一个SOAPPart对象
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Create the main element and namespace
SOAPElement bodyElement =
body.addChildElement(envelope.createName(methodName ,
"tower",
targetNamespace));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
//传送参数新建一个Name对象
Name name = soapFactory.createName("message");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode(messageContext);
message.saveChanges();
return message;
}
public SOAPMessage getMessage(String methodName,String targetNamespace,HashMap<String,String> hm) throws SOAPException,Exception{
//传送参数需要创建Name
SOAPFactory soapFactory = SOAPFactory.newInstance();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//获得一个SOAPPart对象
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Create the main element and namespace
SOAPElement bodyElement =
body.addChildElement(envelope.createName(methodName ,
"ns1",
targetNamespace));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
//传送参数新建一个Name对象
Name name = soapFactory.createName("arg0");
SOAPElement symbol = bodyElement.addChildElement(name);
for (Map.Entry<String, String> m : hm.entrySet()) {
System.out.println("HashMap" + m.getKey() + ":" + m.getValue());
Name symbolName = soapFactory.createName(m.getKey());
SOAPElement symbolNameSOAPElemen = symbol.addChildElement(symbolName);
symbolNameSOAPElemen.addTextNode(m.getValue());
}
message.saveChanges();
return message;
}
}
在本例中Jboss esb服务器提供的web服务只能接受String类型的参数,所以要把soap消息进行格式转换。在服务的消费端通过以下的代码调用格式转换方法:
TransformMessageFormat tmf = new TransformMessageFormatImpl();
String stringSOAPMessage = tmf.transformToString(sm);
格式转换的类和方法如下:
该类的路径在:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\formattransform\impl
package org.jboss.seam.example.booking.commom.formattransform.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.jboss.internal.soa.esb.util.StreamUtils;
import org.jboss.seam.example.booking.commom.formattransform.TransformMessageFormat;
public class TransformMessageFormatImpl implements TransformMessageFormat{
public String transformToString(SOAPMessage sm) throws SOAPException, IOException{
ByteArrayOutputStream s = new ByteArrayOutputStream();
sm.writeTo(s);
byte[] buf=s.toByteArray();
ByteArrayInputStream bin=new ByteArrayInputStream(buf);
String msg = new String(StreamUtils.readStream(bin));
return msg;
}
}
把转换后的Soap消息发送给Jboss ESB服务器,在服务消费者端的调用过程代码如下:
SendSoapMessageToEsb smtEsb = new SendSoapMessageToEsbImpl();
Object o = smtEsb.sendMessageToJBRListener("http", "8765", stringSOAPMessage);
发送消息到Jboss ESB服务器上的类和方法如下:
该类在VSS上的路径如下:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\esb\impl
package org.jboss.seam.example.booking.commom.esb.impl;
import org.jboss.remoting.Client;
import org.jboss.remoting.InvokerLocator;
import org.jboss.seam.example.booking.commom.esb.SendSoapMessageToEsb;
public class SendSoapMessageToEsbImpl implements SendSoapMessageToEsb {
public static String ESBSERVICEIP="192.168.1.101";
public Object sendMessageToJBRListener(String protocol, String port, String message) throws Throwable {
String locatorURI = protocol + "://"+ESBSERVICEIP+":" + port;
InvokerLocator locator = new InvokerLocator(locatorURI);
Client remotingClient = null;
try {
remotingClient = new Client(locator);
remotingClient.connect();
Object response = remotingClient.invoke(message);
return response;
} finally {
if(remotingClient != null) {
remotingClient.disconnect();
}
}
}
}
public static String ESBSERVICEIP="192.168.1.101";这个IP地址表示Jboss ESB服务器的IP地址。
String locatorURI = protocol + "://"+ESBSERVICEIP+":" + port;这行代码可以拼成访问Jboss ESB上发布的Web服务的URL地址。
我们接着看调用端的代码,从Jboss ESB的返回值(其实是Jboss ESB服务器上发布的Web服务再通过转发调用服务提供者端的Web服务,从而得到返回值,服务提供者端的返回值首先把值传回Jboss ESB服务器,Jboss ESB服务器再把值返回到服务调用端。)也是一个Object对象,我们要把这个Object对象转换为我们应用中的真实的对象(比如例子中的ListHotel对象),这个转换我使用了JAXB标准,这个标准主要用于.xml和Java对象之间的互转,因为返回值是SOAP消息,是.xml形式的,同过JAXB标准可以很方便的转换成我们想要的java类(比如ListHotel),在调用端的代码如下:
TransformString tfs = new TransformStringImpl();
Document doc = tfs.transformStringToDocument(o.toString());
NodeList nodeList = doc.getElementsByTagName("ListHotel");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
if(returnContent.length()>0){
String returnContentAnd = "<ListHotel>"+returnContent+"</ListHotel>";
InputStream inputStream = new ByteArrayInputStream(returnContentAnd.getBytes());
JAXBContext context = JAXBContext.newInstance(ListHotel.class);
try {
Unmarshaller um = context.createUnmarshaller();
ListHotel hl = (ListHotel)um.unmarshal(inputStream);
System.out.println("I'm King!"+hl.getElements());
telehotels = hl.getElements();
} catch (JAXBException e) {
e.printStackTrace();
}
}else{
telehotels = null;
}
}catch(Exception e){
e.printStackTrace();
telehotels = null;
} catch (Throwable e) {
e.printStackTrace();
}
从Jboss ESB服务器的返回值先要经过转换,把它转换为Document类型,代码如下:
TransformString tfs = new TransformStringImpl();
Document doc = tfs.transformStringToDocument(o.toString());
转换的类和方法如下:
该类在VSS上的路径如下:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\formattransform\impl
package org.jboss.seam.example.booking.commom.formattransform.impl;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jboss.seam.example.booking.commom.formattransform.TransformString;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class TransformStringImpl implements TransformString{
public Document transformStringToDocument(String s){
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(s)));
return doc;
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String[] getObjectArrayByESBReturnContent(String s){
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(s)));
NodeList nodeList = doc.getElementsByTagName("return");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
if(returnContent.length()>0){
String[] getObjectContest = returnContent.split("</O>");
return getObjectContest;
}else{
return null;
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String[] getPropertyArrayByStringObject(String returnContent){
if(returnContent.length()>0){
String[] getObjectContest = returnContent.split("</A&V>");
return getObjectContest;
}else{
return null;
}
}
}
转换后的Document对象要进行一下截取,重新组装变成适合JAXB转换的XML形式,这个过程如下:
NodeList nodeList = doc.getElementsByTagName("ListHotel");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
String returnContentAnd = "<ListHotel>"+returnContent+"</ListHotel>";
InputStream inputStream = new ByteArrayInputStream(returnContentAnd.getBytes());
把返回值转换为先转换为InputStream对象,这个InputStream对象就符合转换的形式了,可以进行转换了。
要利用JAXB规范进行这样的转换,要进行两步:
①用@XmlRootElement注解标注要转换成的Java类。
Java类如下:
这个Java类在VSS上的路径是:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\collectionbinder
package org.jboss.seam.example.booking.commom.collectionbinder;
import java.util.List;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import org.jboss.seam.example.booking.Hotel;
@XmlRootElement(name="ListHotel")
public class ListHotel {
private List<Hotel> hotel;
public ListHotel() {
}
public ListHotel(List<Hotel> hotel) {
this.hotel = hotel;
}
@XmlElementRef
public List<Hotel> getElements() {
return hotel;
}
public void setElements(List<Hotel> hotel) {
this.hotel = hotel;
}
}
②通过JAXB提供的编组机制,把xml字符转换为Java对象。代码如下:
JAXBContext context = JAXBContext.newInstance(ListHotel.class);
try {
Unmarshaller um = context.createUnmarshaller();
ListHotel hl = (ListHotel)um.unmarshal(inputStream);
System.out.println("I'm King!"+hl.getElements());
telehotels = hl.getElements();
} catch (JAXBException e) {
e.printStackTrace();
}
以上就是我用SAAJ实现Web Service开发的详细过程,文档只是一个参考的作用,要灵活掌握这种方式要翻越其他的资料,认真思考。
这个实例中牵涉到了JBoss ESB服务器,我没有进行详细的介绍,我会在下一个文档中仔细讨论该部分内容。要很好的理解该实例请参考我的Jboss ESB的文档及Vss上的相关代码。
以上是通过Jboss ESB服务器作为中间件转发从消息消费端到消息使用端的的消息的过程,SOA(V1.2)这个文件夹下的工程中还包括了一个服务消费者端直接访问服务提供者端的实例。即:
该类在VSS上的路径为:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\soa\esb\impl
package org.jboss.seam.example.booking.soa.esb.impl;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.commom.esb.BuildSoapMessage;
import org.jboss.seam.example.booking.commom.esb.SendSoapMessage;
import org.jboss.seam.example.booking.commom.esb.impl.BuildSoapMessageImpl;
import org.jboss.seam.example.booking.commom.esb.impl.SendSoapMessageImpl;
import org.jboss.seam.example.booking.commom.formattransform.TransformMethodName;
import org.jboss.seam.example.booking.commom.formattransform.impl.TransformMethodNameImpl;
import org.jboss.seam.example.booking.soa.esb.TeteDataHotelSave;
@Stateful
@Name("saveTeteDataHotel")
@Restrict("#{identity.loggedIn}")
public class TeteDataHotelSaveImpl implements TeteDataHotelSave
{
@In(required=false)
@Out(required=false)
private Hotel hotel;
@Begin
public void selectHotel(Hotel selectedHotel)
{
//Hotel h = new Hotel();
hotel = selectedHotel;
}
public void seveHotel(Hotel hotel)
{
String ipAddress = hotel.getIpAddress();
System.out.println("yuexiangcheng,test!!!!!========"+ipAddress);
TransformMethodName tmn = new TransformMethodNameImpl();
Field[] f = hotel.getClass().getDeclaredFields();
HashMap<String,String> hm = new HashMap();
for(int i = 0;i< f.length;i++){
try {
String attributeName = f[i].getName();
System.out.println("attributeNameattributeNameattributeNameattributeNameattributeNameattributeName"+attributeName);
String motherName = tmn.getGetMethodByAttribute(attributeName);
Method method = hotel.getClass().getDeclaredMethod(motherName,null);
String attributeValue = method.invoke(hotel, null).toString();
System.out.println("attributeValueattributeValueattributeValueattributeValueattributeValueattributeValue"+attributeValue);
hm.put(attributeName, attributeValue);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
BuildSoapMessage bsm = new BuildSoapMessageImpl();
SendSoapMessage ssm = new SendSoapMessageImpl();
try {
SOAPMessage sm = bsm.getMessage("updateHotelObject", "http://tower/ehr_DEV", hm);
SOAPMessage result = ssm.send(sm, "http://"+ipAddress+":8080/jboss-seam-booking-jboss-seam-booking/HotelObjectImpl");
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Transformer transformer =
transformerFactory.newTransformer();
Source sourceContent = result.getSOAPPart().getContent();
StreamResult resultPrint = new StreamResult(System.out);
transformer.transform(sourceContent, resultPrint);
System.out.println();
} catch (SOAPException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
} catch (Exception e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
@End
public void cancel() {}
@Remove
public void destroy() {}
}
该过程是服务消费者端修改了从服务提供者端检索到的数据,并对其进行了修改再保持到服务提供者端。具体的过程和上例查不多,请详细研究在VSS上的代码。值得注意的是该例中用到了JAXB的解组功能。
以上就是我实现Web Service的两种方法,因为能力有限,所以写的不好,仅供参考。希望对大家有帮助,谢谢。
1、 什么是Web Service
Web services是建立可互操作的分布式应用程序的新平台。
Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。
Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,Web service平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。
基础的 Web Services 平台是 XML + HTTP。
HTTP 协议是最常用的因特网协议。
XML 提供了一种可用于不同的平台和编程语言之间的语言。
Web services 平台是简单的可共同操作的消息收发框架。它仍然缺少许多诸如安全和路由等重要的特性。但是,一旦 SOAP 变得更加高级,这些事项就会得到解决。
Web services 有望使应用程序更加容易通信。
★ Web services 把 Web 应用程序提升到了另外一个层面
通过使用 Web services,您的应用程序可向全世界发布功能或消息。
Web services 使用 XML 来编解码数据,并使用 SOAP 借由开放的协议来传输数据。
通过 Web services,您的会计部门的 Win 2k 服务器可与 IT 供应商的 UNIX 服务器进行连接。
★ Web services 有两种类型的应用
可重复使用的应用程序组件
有一些功能是不同的应用程序常常会用到的。那么为什么要周而复始地开发它们呢?
Web services 可以把应用程序组件作为服务来提供,比如汇率转换、天气预报或者甚至是语言翻译等等。
比较理想的情况是,每种应用程序组件只有一个最优秀的版本,这样任何人都可以在其应用程序中使用它。
连接现有的软件
通过为不同的应用程序提供一种链接其数据的途径,Web services有助于解决协同工作的问题。
通过使用 Web services,您可以在不同的应用程序与平台之间来交换数据。
★ Web Services 拥有两种基本的元素。
它们是:SOAP及WSDL
(1)什么是 SOAP?
SOAP 指简易对象访问协议
SOAP 是一种通信协议
SOAP 用于应用程序之间的通信
SOAP 是一种用于发送消息的格式
SOAP 被设计用来通过因特网进行通信
SOAP 独立于平台
SOAP 独立于语言
SOAP 基于 XML
SOAP 很简单并可扩展
SOAP 允许您绕过防火墙
SOAP 将作为 W3C 标准来发展
(2)什么是 WSDL?
WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言。
WSDL 指网络服务描述语言
WSDL 使用 XML 编写
WSDL 是一种 XML 文档
WSDL 用于描述网络服务
WSDL 也可用于定位网络服务
WSDL 还不是 W3C 标准
2、 什么是JWS
JWS(Java Web Service)是Java应用平台上专门用于开发Web服务系统及面向服务系统的产品,它的最新版本是2.0,Java EE 5和Java SE 6都对JWS 2.0提供支持。
在JWS 2.0,Java定义了一系列新的标准,JMS本身也包含了一些工具,如JAX-WS 2.0,JAXB 2.0,JAXP 1.4,SAAJ 1.3以及WS-Metadata等。
面向服务的系统往往由多个具有不同的子功能的独立组件构成,通过他们之间良好的相互协作,可以实现复杂的需求。面向服务系统的这个特点,要求独立组建之间有公共的接口,这些用于交换数据的公共接口有良好的定义。由于要实现组件之间的数据通信,这些具有良好定义的接口就必须要被别的组件识别并正确理解,才能实现协作。
在定义了公共的接口后,还存在具体的数据交换问题,即双方需要遵循一个共同的数据交换标准,这个数据交换标准称为协议。要在独立的组件之间进行通信,需要一系列标准来严格规定数据通信的格式和规则。
Web Service的出现解决了上述问题,利用WSDL定义统一的接口格式,用SOAP消息统一输入/输出参数的统一格式。SOAP消息可以由多种途径传递,比如,通过HTTP,SMTP及JMS协议传递。以HTTP为例,在服务使用端,WSDL的接口定义可以通过HTTP-GET请求获取,而SOAP应答消息及回复消息的传输可以通过HTTP-POST请求来实现。这样,基于WSDL和SOAP消息机制就可以满足面向服务应用系统开发的需求。
Web Service平台架构主要由三部分构成:序列化及反序列化子系统、调用子系统及发布子系统。这三个子系统并不受具体语言的限制,也不受平台和框架的限制,无论使用Java语言还是.NET语言,无论使用Axis平台还是JWS来开发web服务,都会涉及这三个最基本的功能模块。
(1)序列化及反序列化
在JMS中将一个Java对象转化为一个XML元素的过程,称为序列化。反之将一个XML元素转化为相应的Java
对象的过程,称为反序列化。序列化和反序列化的过程要依赖于Java类和XML-Scheme之间的映射关系,JWS有独立
的序列化和反序列化子系统用来负责完成这些映射及转化。
在web服务的客户端,序列化过程将参数转化为xml结点,进而封装成Soap请求消息,发送至服务器端的web服务端点。获得返回值时,反序列化过程启动,它将返回值从SOAP消息中指定的xml结点中取出,然后将它转化为客户端相对应的Java对象。
转化规则的定义在JWS中是通过JAXB的注释来完成的。新版的JAXB简化了绑定规则的描述,它允许直接将规则以注解的形式写入Java类。
例如:
@Entity
@Name("hotel")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlType(name="", propOrder = {
"id",
"img",
"name",
"address",
"city",
"state",
"zip",
"country",
"price",
"ipAddress"
})
@XmlRootElement(name="Hotel")
public class Hotel implements Serializable
{
private Long id;
private String img;
private String name;
private String address;
private String city;
private String state;
private String zip;
private String country;
private BigDecimal price;
private String ipAddress = "192.168.1.112";
@Id @GeneratedValue
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
@Length(max = 50)
@NotNull
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
@Length(max=50) @NotNull
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Length(max=100) @NotNull
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
@Length(max=40) @NotNull
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
@Length(min=4, max=6) @NotNull
public String getZip()
{
return zip;
}
public void setZip(String zip)
{
this.zip = zip;
}
@Length(min=2, max=10) @NotNull
public String getState()
{
return state;
}
public void setState(String state)
{
this.state = state;
}
@Length(min=2, max=40) @NotNull
public String getCountry()
{
return country;
}
public void setCountry(String country)
{
this.country = country;
}
@Column(precision=6, scale=2)
public BigDecimal getPrice()
{
return price;
}
public void setPrice(BigDecimal price)
{
this.price = price;
}
@Transient
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
@Override
public String toString()
{
return "Hotel(" + name + "," + address + "," + city + "," + zip + ")";
}
}
(2)服务调用的过程
在面向服务的分布式系统中,一般将传统的客户服务器框架中的客户端Client称为服务的消费者,而将服务器端称为服务的提供者。
按照现在的web服务标准,一个服务被调用时,在服务的提供端大致的处理过程如下:
①接受并预处理SOAP请求消息,例如效验,处理SOAP消息报文头。
②从消息中获取该消息希望调用的接口和具体操作。
③利用web服务提供的支持,找到具体的实现对象,并调用该对象的接口。这个对象可以由不同的语言实现。JWS支持从WSDL到Java的映射,可以通过WSDL找到与它相对应的Java服务端点实现类。
④使用序列化工具的反序列化过程,将SOAP请求消息中的服务请求参数取出,传递给步骤3中的目标对象的相应函数。
⑤目标Java对象执行相应的操作,将计算的结果以对象形式返回。
⑥使用序列化工具的序列化过程,根据wsdl中的定义,将步骤5中的结果对象序列化成XML元素,并封装到SOAP回复消
息中。
⑦将步骤6中的SOAP回复消息发送回服务调用端。
与之对应的,在服务使用端的调用过程如下:
①首先创建服务端点接口对象SEI(Service Endpoint Interface),在Web服务客户端一般都会有相应的工厂类完成SEI对象的实例化。在JWS中,SEI对象一般是由Java代理来实现的。
②客户端通过SEI调用其中封装的web服务接口。
③利用序列化工具的序列化过程,根据WSDL的定义,将客户端的调用接口的参数转化成XML元素,再将该元素封装在SOAP请求消息里。
④在同步模式下,在SOAP请求消息发出后,客户端会等待SOAP应答消息;异步模式下,客户端顺序执行后续代码,直到通过监听器接收到SOAP请求消息里。
⑤解析从服务器端获得的SOAP应答消息,使用序列化工具中的反序列化过程,将SOAP应答消息中的数据转化成客户端对象,该对象的值就是被调用服务的返回值。
(3)web服务的发布
以JMS为例,web服务发布系统的主要功能
①以URL的形式公开被发布的WEB服务的WSDL文件,并绑定SOAP请求消息和Java目标类。
②发布JAVA目标文件(例如Java Object文件,WAR文件,JAR文件及相关配置文件等)。
③配置序列化和反序列化子系统。
④配置web服务端点监听器和SOAP消息预处理进程。
二、 web service的几种开发及调用方式
(1)用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用。
实例如下(实例中应用的EJB容器为Jboss,所有代码是基于JBoss Seam架构来编写的):
①服务的提供者端<提供服务端的代码>:
服务的提供者端的任务是暴露一个web service以供外部使用,本例的web service是通过JavaEE平台提供的@java.jws.WebService注解来实现的。
以下代码的路径是VSS上 前期调查文件夹下SOA\web service\用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用\tele\book\src\org\jboss\seam\example\booking\ws\impl,用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用文件夹下包括两个文件夹:local,tele。tele文件夹下放服务的提供者端的工程和打好的EAR包。local文件夹下放服务的消费者端的工程和打好的EAR包。
package org.jboss.seam.example.booking.ws.impl;
import static org.jboss.seam.ScopeType.SESSION;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.User;
import org.jboss.seam.example.booking.ws.HotelObject;
@Stateless
/**实例是使用了两个JBoss应用服务器,该代码是服务提供者端的代码,所以使用了@Remote注解,实现远程接口。。*/
@Remote (HotelObject.class)
@WebService
public class HotelObjectImpl implements HotelObject {
@PersistenceContext
private EntityManager em;
public List<Hotel> getHotelObject(String hotelName) {
List<Hotel> results = em.createQuery("select h from Hotel h where h.name like"+ " '%"+hotelName+"%'")
.getResultList();
if(results.size()>0){
return results;
}
return null;
}
public String updateHotelObject(Hotel h){
try{
System.out.println(h);
System.out.println(h.getName());
em.merge(h);
}catch(Exception e ){
e.printStackTrace();
return "error";
}
return "success";
}
}
上面的类继承了一个接口,接口类的路径是:VSS上前期调查文件夹下SOA\web service\用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用\tele\book\src\org\jboss\seam\example\booking\ws。
package org.jboss.seam.example.booking.ws;
import java.util.List;
import org.jboss.seam.example.booking.Hotel;
public interface HotelObject {
public List<Hotel> getHotelObject(String hotelName);
public String updateHotelObject(Hotel h);
}
上面的@WebService注解指名这是一个Web Service。打开Ant文件,执行desploy业务。部署完成后,通过JBoss管理平台查看刚才部署的Web Service,输入http://localhost:8080/jbossws/进入JBoss Web Service的查看界面,可以看到View a list of deployed services链接,单击View a list of deployed services链接后,可以查看已经发布的Web Service的URL地址,单击该地址就可以查看生成的WSDL文。
这就是服务提供端的主要代码,先用注解定义了一个web服务,这个web服务提供了两个方法,这两个方法可以接收从远程传过来的参数。服务的消费着可以通过上面的URL地址访问该服务。
(2)服务的消费者端<使用服务端的代码>
要调用web服务,我们可以通过好多方式,其中的一种方式是通过wsimport工具(在JDK1.6中,Sun已经为用户提供了wsimport工具)生成辅助类来调用web服务。
在VSS上web Service文件夹中有一个叫做jaxws-ri的文件包里面包含了wsimport工具,本例的辅助类就是用它直接生成的。要用wsimport工具生成辅助类,首先要在dos环境下打开wsimport工具所在的目录,比如wsimport工具的本地路径:
Dos下打开wsimport工具所在的路径。
在wsimport路径下输入如下内容:
wsimport.bat -keep -d ../build/classes/client http://192.168.1.106:8080/WsHelloWorld/HelloWorldBean?wsdl
其中../build/classes/client表示生成的辅助类存放的路径,http://192.168.1.106:8080/WsHelloWorld/HelloWorldBean?wsdl表示要调用的web服务的WSDL文地址,其中192.168.1.106表示服务提供端的IP地址。
生成的辅助类如下图所示:
把生成的辅助java类拷贝到我们的工程中
然后实例化一个生成的辅助类的对象,通过该对象调用服务提供者提供的方法<即getHotelObjec()>,去检索符合条件的记录。
该类位于VSS上如下路径下;
SOA\Web Servic\用EJB容器模型开发Web Service,用wsimport工具生成辅助类进行调用\local\book\src\org\jboss\seam\example\booking
package org.jboss.seam.example.booking;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.ws.impl.Hotel;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImpl;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImplService;
@Stateful
@Name("teledataHotelSearch")
@Scope(ScopeType.SESSION)
@Restrict("#{identity.loggedIn}")
public class TeledateHotelSearchingAction implements TeledateHotelSearching
{
@PersistenceContext
private EntityManager em;
private String searchString;
@DataModel
private List<Hotel> telehotels;
public void find()
{
queryHotels();
}
private void queryHotels() {
/**实例化生成的辅助类的对象,通过该对象调用远程的web service。*/
HotelObjectImplService service;
try
{
service = new HotelObjectImplService();
HotelObjectImpl hotelObjectImpl = service.getHotelObjectImplPort();
List<Hotel> result = hotelObjectImpl.getHotelObject(this.getSearchString());
System.out.println(result.size());
if(result.size()>0){
telehotels = result;
}else{
telehotels =null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getSearchString()
{
return searchString;
}
public void setSearchString(String searchString)
{
this.searchString = searchString;
}
@Remove
public void destroy() {}
@Override
public void cancel() {
// TODO 自动生成的方法存根
}
}
还有一个类是为了保存修改了的服务提供者(即远程的Web Service)返回的Hotel对象,必须调用服务提供者提供的保存Hotel对象的方法<即updateHotelObject ()>。
package org.jboss.seam.example.booking;
import static javax.persistence.PersistenceContextType.EXTENDED;
import java.util.Calendar;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.core.Events;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImpl;
import org.jboss.seam.example.booking.ws.impl.HotelObjectImplService;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;
@Stateful
@Name("saveTeteDataHotel")
@Restrict("#{identity.loggedIn}")
public class SaveTeteDataHotelAction implements SaveTeteDataHotel
{
@Begin
public void seveHotel(Hotel hotel)
{
HotelObjectImplService service;
try
{
service = new HotelObjectImplService();
HotelObjectImpl hotelObjectImpl = service.getHotelObjectImplPort();
String result = hotelObjectImpl.updateHotelObject(this.conversionHotel(hotel));
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
public org.jboss.seam.example.booking.ws.impl.Hotel conversionHotel(Hotel hotel){
org.jboss.seam.example.booking.ws.impl.Hotel h = new org.jboss.seam.example.booking.ws.impl.Hotel();
h.setAddress(hotel.getAddress());
h.setCity(hotel.getCity());
h.setCountry(hotel.getCountry());
h.setId(hotel.getId());
h.setImg(hotel.getImg());
h.setName(hotel.getName());
h.setPrice(hotel.getPrice());
h.setState(hotel.getState());
h.setZip(hotel.getZip());
return h;
}
@End
public void cancel() {}
@Remove
public void destroy() {}
}
以上类中有一点值得注意,就是服务消费者中的Hotel对象不能直接用于保存,必须经过转换,转换成生成的辅助类中的org.jboss.seam.example.booking.ws.impl.Hotel类,才能进行保存,上面的conversionHotel(Hotel hotel)方法就是为了进行该转换。
以上就是该种使用web service的几个重要的点,通过以上各步就可以访问远程发布的web服务,完整的过程请参考Vss上Dome工程。
(2)利用SAAJ协议动态生成SOAP消息访问服务提供者端的web service。
第一种方式是利用wsimpot工具来生成辅助类来实现对服务提供者端的web service的访问,由于生成的辅助类特别多,而且灵活性差。下面我们介绍用SAAJ协议动态生成SOAP消息来访问服务提供者端的web service。
①服务提供者端的代码
该类的在VSS上:
EHR\SOA\SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\ws\impl下
package org.jboss.seam.example.booking.ws.impl;
import static org.jboss.seam.ScopeType.SESSION;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.User;
import org.jboss.seam.example.booking.ws.HotelObject;
@Stateless
@Remote (HotelObject.class)
@WebService(name = "HotelObject", targetNamespace = "http://tower/ehr_DEV")
public class HotelObjectImpl implements HotelObject {
@PersistenceContext
private EntityManager em;
@WebResult(name="Hotel")
public List<Hotel> getHotelObject(String hotelName) {
List<Hotel> results = em.createQuery("select h from Hotel h where h.name like"+ " '%"+hotelName+"%'")
.getResultList();
if(results.size()>0){
return results;
}
return null;
}
public String updateHotelObject(Hotel h){
try{
System.out.println(h);
System.out.println(h.getName());
em.merge(h);
}catch(Exception e ){
e.printStackTrace();
return "error";
}
return "success";
}
}
该web服务提供了两个方法,getHotelObject(String hotelName)方法接收远程的的参数,通过该参数查找符合条件的Hotel对象;updateHotelObject(Hotel h)方法用来保存修改后的对象。
②服务调用者端的代码
该类的在VSS上:
EHR\SOA\ SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\soa\esb\impl下
本例使用了Jboss ESB,其实服务调用端首先发送请求到Jboss ESB服务器上,Jboss ESB服务器上也定义了一些web服务,来接受这些请求,接受到请求消息后,对消息进行进一步的加工或者直接把消息转发给真正的消息提供者端。
下面的代码展示了服务消费端如何通过ESB服务器,去调用服务提供者端提供的服务。
package org.jboss.seam.example.booking.soa.esb.impl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.soap.SOAPMessage;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.commom.collectionbinder.ListHotel;
import org.jboss.seam.example.booking.commom.esb.BuildSoapMessage;
import org.jboss.seam.example.booking.commom.esb.SendSoapMessageToEsb;
import org.jboss.seam.example.booking.commom.esb.impl.BuildSoapMessageImpl;
import org.jboss.seam.example.booking.commom.esb.impl.SendSoapMessageToEsbImpl;
import org.jboss.seam.example.booking.commom.formattransform.TransformMessageFormat;
import org.jboss.seam.example.booking.commom.formattransform.TransformString;
import org.jboss.seam.example.booking.commom.formattransform.impl.TransformMessageFormatImpl;
import org.jboss.seam.example.booking.commom.formattransform.impl.TransformStringImpl;
import org.jboss.seam.example.booking.soa.esb.TeledateHotelSearching;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@Stateful
@Name("teledataHotelSearch")
@Scope(ScopeType.SESSION)
@Restrict("#{identity.loggedIn}")
public class TeledateHotelSearchingImpl implements TeledateHotelSearching
{
@PersistenceContext
private EntityManager em;
private String searchString;
@DataModel
private List<Hotel> telehotels;
public void find()
{
getHotelObject(this.getSearchString());
}
public void getHotelObject(String searchString) {
try{
BuildSoapMessage bsm = new BuildSoapMessageImpl();
SOAPMessage sm = bsm.getMessage("sayGoodbye", "http://webservice_producer/goodbyeworld", searchString);
TransformMessageFormat tmf = new TransformMessageFormatImpl();
String stringSOAPMessage = tmf.transformToString(sm);
SendSoapMessageToEsb smtEsb = new SendSoapMessageToEsbImpl();
Object o = smtEsb.sendMessageToJBRListener("http", "8765", stringSOAPMessage);
System.out.println("wo de ma ya!!!"+o.toString());
TransformString tfs = new TransformStringImpl();
Document doc = tfs.transformStringToDocument(o.toString());
NodeList nodeList = doc.getElementsByTagName("ListHotel");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
if(returnContent.length()>0){
String returnContentAnd = "<ListHotel>"+returnContent+"</ListHotel>";
InputStream inputStream = new ByteArrayInputStream(returnContentAnd.getBytes());
JAXBContext context = JAXBContext.newInstance(ListHotel.class);
try {
Unmarshaller um = context.createUnmarshaller();
ListHotel hl = (ListHotel)um.unmarshal(inputStream);
System.out.println("I'm King!"+hl.getElements());
telehotels = hl.getElements();
} catch (JAXBException e) {
e.printStackTrace();
}
}else{
telehotels = null;
}
}catch(Exception e){
e.printStackTrace();
telehotels = null;
} catch (Throwable e) {
e.printStackTrace();
}
}
public String getSearchString()
{
return searchString;
}
public void setSearchString(String searchString)
{
this.searchString = searchString;
}
@Remove
public void destroy() {}
@Override
public void cancel() {
searchString = "";
telehotels = null;
}
}
在getHotelObject(String searchString)方法中,首先通过BuildSoapMessage类提供的getMessage()方法生成要发送的SOAP消息。(调用的代码如下:)
BuildSoapMessage bsm = new BuildSoapMessageImpl();
SOAPMessage sm = bsm.getMessage("sayGoodbye", "http://webservice_producer/goodbyeworld", searchString);
BuildSoapMessage类及代码如下:
该类的在vss上的路径如下:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\esb\impl
package org.jboss.seam.example.booking.commom.esb.impl;
import java.util.HashMap;
import java.util.Map;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import org.jboss.seam.example.booking.commom.esb.BuildSoapMessage;
public class BuildSoapMessageImpl implements BuildSoapMessage{
public static final SOAPConnection getSOAPConnection(){
SOAPConnectionFactory soapConnFactory;
SOAPConnection connection;
try {
soapConnFactory = SOAPConnectionFactory.newInstance();
connection = soapConnFactory.createConnection();
return connection;
} catch (UnsupportedOperationException e) {
e.printStackTrace();
return null;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public static final SOAPMessage getSOAPMessage(){
MessageFactory messageFactory;
SOAPMessage message;
try {
messageFactory = MessageFactory.newInstance();
message = messageFactory.createMessage();
return message;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public Name getName(String param){
SOAPFactory soapFactory;
try {
soapFactory = SOAPFactory.newInstance();
Name name = soapFactory.createName(param); //"arg0"
return name;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public SOAPElement getBodyElement(SOAPMessage message,String param1,String param2,String param3){
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope;
SOAPBody body;
SOAPElement bodyElement;
try {
envelope = soapPart.getEnvelope();
body = envelope.getBody();
bodyElement = body.addChildElement(envelope.createName(param1,//"sayHello" ,
param1,//"ns1",
param1));//"http://webservice_consumer1/helloworld"));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
return bodyElement;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public SOAPElement addTextNode(SOAPMessage message,String param1,String param2,String param3){
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope;
SOAPBody body;
SOAPElement bodyElement;
try {
envelope = soapPart.getEnvelope();
body = envelope.getBody();
bodyElement = body.addChildElement(envelope.createName(param1,//"sayHello" ,
param1,//"ns1",
param1));//"http://webservice_consumer1/helloworld"));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
return bodyElement;
} catch (SOAPException e) {
e.printStackTrace();
return null;
}
}
public SOAPMessage getMessage(String methodName,String targetNamespace,String messageContext) throws SOAPException,Exception{
//传送参数需要创建Name
SOAPFactory soapFactory = SOAPFactory.newInstance();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//获得一个SOAPPart对象
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Create the main element and namespace
SOAPElement bodyElement =
body.addChildElement(envelope.createName(methodName ,
"tower",
targetNamespace));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
//传送参数新建一个Name对象
Name name = soapFactory.createName("message");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode(messageContext);
message.saveChanges();
return message;
}
public SOAPMessage getMessage(String methodName,String targetNamespace,HashMap<String,String> hm) throws SOAPException,Exception{
//传送参数需要创建Name
SOAPFactory soapFactory = SOAPFactory.newInstance();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//获得一个SOAPPart对象
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Create the main element and namespace
SOAPElement bodyElement =
body.addChildElement(envelope.createName(methodName ,
"ns1",
targetNamespace));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
//传送参数新建一个Name对象
Name name = soapFactory.createName("arg0");
SOAPElement symbol = bodyElement.addChildElement(name);
for (Map.Entry<String, String> m : hm.entrySet()) {
System.out.println("HashMap" + m.getKey() + ":" + m.getValue());
Name symbolName = soapFactory.createName(m.getKey());
SOAPElement symbolNameSOAPElemen = symbol.addChildElement(symbolName);
symbolNameSOAPElemen.addTextNode(m.getValue());
}
message.saveChanges();
return message;
}
}
在本例中Jboss esb服务器提供的web服务只能接受String类型的参数,所以要把soap消息进行格式转换。在服务的消费端通过以下的代码调用格式转换方法:
TransformMessageFormat tmf = new TransformMessageFormatImpl();
String stringSOAPMessage = tmf.transformToString(sm);
格式转换的类和方法如下:
该类的路径在:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\formattransform\impl
package org.jboss.seam.example.booking.commom.formattransform.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.jboss.internal.soa.esb.util.StreamUtils;
import org.jboss.seam.example.booking.commom.formattransform.TransformMessageFormat;
public class TransformMessageFormatImpl implements TransformMessageFormat{
public String transformToString(SOAPMessage sm) throws SOAPException, IOException{
ByteArrayOutputStream s = new ByteArrayOutputStream();
sm.writeTo(s);
byte[] buf=s.toByteArray();
ByteArrayInputStream bin=new ByteArrayInputStream(buf);
String msg = new String(StreamUtils.readStream(bin));
return msg;
}
}
把转换后的Soap消息发送给Jboss ESB服务器,在服务消费者端的调用过程代码如下:
SendSoapMessageToEsb smtEsb = new SendSoapMessageToEsbImpl();
Object o = smtEsb.sendMessageToJBRListener("http", "8765", stringSOAPMessage);
发送消息到Jboss ESB服务器上的类和方法如下:
该类在VSS上的路径如下:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\esb\impl
package org.jboss.seam.example.booking.commom.esb.impl;
import org.jboss.remoting.Client;
import org.jboss.remoting.InvokerLocator;
import org.jboss.seam.example.booking.commom.esb.SendSoapMessageToEsb;
public class SendSoapMessageToEsbImpl implements SendSoapMessageToEsb {
public static String ESBSERVICEIP="192.168.1.101";
public Object sendMessageToJBRListener(String protocol, String port, String message) throws Throwable {
String locatorURI = protocol + "://"+ESBSERVICEIP+":" + port;
InvokerLocator locator = new InvokerLocator(locatorURI);
Client remotingClient = null;
try {
remotingClient = new Client(locator);
remotingClient.connect();
Object response = remotingClient.invoke(message);
return response;
} finally {
if(remotingClient != null) {
remotingClient.disconnect();
}
}
}
}
public static String ESBSERVICEIP="192.168.1.101";这个IP地址表示Jboss ESB服务器的IP地址。
String locatorURI = protocol + "://"+ESBSERVICEIP+":" + port;这行代码可以拼成访问Jboss ESB上发布的Web服务的URL地址。
我们接着看调用端的代码,从Jboss ESB的返回值(其实是Jboss ESB服务器上发布的Web服务再通过转发调用服务提供者端的Web服务,从而得到返回值,服务提供者端的返回值首先把值传回Jboss ESB服务器,Jboss ESB服务器再把值返回到服务调用端。)也是一个Object对象,我们要把这个Object对象转换为我们应用中的真实的对象(比如例子中的ListHotel对象),这个转换我使用了JAXB标准,这个标准主要用于.xml和Java对象之间的互转,因为返回值是SOAP消息,是.xml形式的,同过JAXB标准可以很方便的转换成我们想要的java类(比如ListHotel),在调用端的代码如下:
TransformString tfs = new TransformStringImpl();
Document doc = tfs.transformStringToDocument(o.toString());
NodeList nodeList = doc.getElementsByTagName("ListHotel");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
if(returnContent.length()>0){
String returnContentAnd = "<ListHotel>"+returnContent+"</ListHotel>";
InputStream inputStream = new ByteArrayInputStream(returnContentAnd.getBytes());
JAXBContext context = JAXBContext.newInstance(ListHotel.class);
try {
Unmarshaller um = context.createUnmarshaller();
ListHotel hl = (ListHotel)um.unmarshal(inputStream);
System.out.println("I'm King!"+hl.getElements());
telehotels = hl.getElements();
} catch (JAXBException e) {
e.printStackTrace();
}
}else{
telehotels = null;
}
}catch(Exception e){
e.printStackTrace();
telehotels = null;
} catch (Throwable e) {
e.printStackTrace();
}
从Jboss ESB服务器的返回值先要经过转换,把它转换为Document类型,代码如下:
TransformString tfs = new TransformStringImpl();
Document doc = tfs.transformStringToDocument(o.toString());
转换的类和方法如下:
该类在VSS上的路径如下:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\formattransform\impl
package org.jboss.seam.example.booking.commom.formattransform.impl;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jboss.seam.example.booking.commom.formattransform.TransformString;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class TransformStringImpl implements TransformString{
public Document transformStringToDocument(String s){
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(s)));
return doc;
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String[] getObjectArrayByESBReturnContent(String s){
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(s)));
NodeList nodeList = doc.getElementsByTagName("return");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
if(returnContent.length()>0){
String[] getObjectContest = returnContent.split("</O>");
return getObjectContest;
}else{
return null;
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String[] getPropertyArrayByStringObject(String returnContent){
if(returnContent.length()>0){
String[] getObjectContest = returnContent.split("</A&V>");
return getObjectContest;
}else{
return null;
}
}
}
转换后的Document对象要进行一下截取,重新组装变成适合JAXB转换的XML形式,这个过程如下:
NodeList nodeList = doc.getElementsByTagName("ListHotel");
Element element = (Element)nodeList.item(0);
String returnContent = element.getTextContent();
String returnContentAnd = "<ListHotel>"+returnContent+"</ListHotel>";
InputStream inputStream = new ByteArrayInputStream(returnContentAnd.getBytes());
把返回值转换为先转换为InputStream对象,这个InputStream对象就符合转换的形式了,可以进行转换了。
要利用JAXB规范进行这样的转换,要进行两步:
①用@XmlRootElement注解标注要转换成的Java类。
Java类如下:
这个Java类在VSS上的路径是:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\commom\collectionbinder
package org.jboss.seam.example.booking.commom.collectionbinder;
import java.util.List;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import org.jboss.seam.example.booking.Hotel;
@XmlRootElement(name="ListHotel")
public class ListHotel {
private List<Hotel> hotel;
public ListHotel() {
}
public ListHotel(List<Hotel> hotel) {
this.hotel = hotel;
}
@XmlElementRef
public List<Hotel> getElements() {
return hotel;
}
public void setElements(List<Hotel> hotel) {
this.hotel = hotel;
}
}
②通过JAXB提供的编组机制,把xml字符转换为Java对象。代码如下:
JAXBContext context = JAXBContext.newInstance(ListHotel.class);
try {
Unmarshaller um = context.createUnmarshaller();
ListHotel hl = (ListHotel)um.unmarshal(inputStream);
System.out.println("I'm King!"+hl.getElements());
telehotels = hl.getElements();
} catch (JAXBException e) {
e.printStackTrace();
}
以上就是我用SAAJ实现Web Service开发的详细过程,文档只是一个参考的作用,要灵活掌握这种方式要翻越其他的资料,认真思考。
这个实例中牵涉到了JBoss ESB服务器,我没有进行详细的介绍,我会在下一个文档中仔细讨论该部分内容。要很好的理解该实例请参考我的Jboss ESB的文档及Vss上的相关代码。
以上是通过Jboss ESB服务器作为中间件转发从消息消费端到消息使用端的的消息的过程,SOA(V1.2)这个文件夹下的工程中还包括了一个服务消费者端直接访问服务提供者端的实例。即:
该类在VSS上的路径为:
SOA(V1.2)\Request endpoint(192.168.1.112)\booking\src\org\jboss\seam\example\booking\soa\esb\impl
package org.jboss.seam.example.booking.soa.esb.impl;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.security.Restrict;
import org.jboss.seam.example.booking.Hotel;
import org.jboss.seam.example.booking.commom.esb.BuildSoapMessage;
import org.jboss.seam.example.booking.commom.esb.SendSoapMessage;
import org.jboss.seam.example.booking.commom.esb.impl.BuildSoapMessageImpl;
import org.jboss.seam.example.booking.commom.esb.impl.SendSoapMessageImpl;
import org.jboss.seam.example.booking.commom.formattransform.TransformMethodName;
import org.jboss.seam.example.booking.commom.formattransform.impl.TransformMethodNameImpl;
import org.jboss.seam.example.booking.soa.esb.TeteDataHotelSave;
@Stateful
@Name("saveTeteDataHotel")
@Restrict("#{identity.loggedIn}")
public class TeteDataHotelSaveImpl implements TeteDataHotelSave
{
@In(required=false)
@Out(required=false)
private Hotel hotel;
@Begin
public void selectHotel(Hotel selectedHotel)
{
//Hotel h = new Hotel();
hotel = selectedHotel;
}
public void seveHotel(Hotel hotel)
{
String ipAddress = hotel.getIpAddress();
System.out.println("yuexiangcheng,test!!!!!========"+ipAddress);
TransformMethodName tmn = new TransformMethodNameImpl();
Field[] f = hotel.getClass().getDeclaredFields();
HashMap<String,String> hm = new HashMap();
for(int i = 0;i< f.length;i++){
try {
String attributeName = f[i].getName();
System.out.println("attributeNameattributeNameattributeNameattributeNameattributeNameattributeName"+attributeName);
String motherName = tmn.getGetMethodByAttribute(attributeName);
Method method = hotel.getClass().getDeclaredMethod(motherName,null);
String attributeValue = method.invoke(hotel, null).toString();
System.out.println("attributeValueattributeValueattributeValueattributeValueattributeValueattributeValue"+attributeValue);
hm.put(attributeName, attributeValue);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
BuildSoapMessage bsm = new BuildSoapMessageImpl();
SendSoapMessage ssm = new SendSoapMessageImpl();
try {
SOAPMessage sm = bsm.getMessage("updateHotelObject", "http://tower/ehr_DEV", hm);
SOAPMessage result = ssm.send(sm, "http://"+ipAddress+":8080/jboss-seam-booking-jboss-seam-booking/HotelObjectImpl");
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Transformer transformer =
transformerFactory.newTransformer();
Source sourceContent = result.getSOAPPart().getContent();
StreamResult resultPrint = new StreamResult(System.out);
transformer.transform(sourceContent, resultPrint);
System.out.println();
} catch (SOAPException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
} catch (Exception e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
@End
public void cancel() {}
@Remove
public void destroy() {}
}
该过程是服务消费者端修改了从服务提供者端检索到的数据,并对其进行了修改再保持到服务提供者端。具体的过程和上例查不多,请详细研究在VSS上的代码。值得注意的是该例中用到了JAXB的解组功能。
以上就是我实现Web Service的两种方法,因为能力有限,所以写的不好,仅供参考。希望对大家有帮助,谢谢。
发表评论
-
LOG4j
2012-04-01 15:34 971本文章摘自网络 ... -
javaBean对应Hibernate映射类型
2012-01-04 14:57 4218Hibernate映射类型分为两种:内置的映射类型和 ... -
java 编码 UTF-8、ISO-8859-1、GBK
2011-09-22 19:10 1325java 编码 UTF-8、ISO-8859-1 ... -
java排序归总
2011-02-23 17:41 1084package org.rut.util.algorithm. ... -
java乱码转换原理
2010-09-25 16:32 1420一、Java中文问题的由来 ... -
sql 基础 [一个常见的面试题]
2010-08-30 14:24 1693--create database Dom --on --( ... -
jquery-autocomplete 自动填充插件参数使用说明
2010-08-30 12:42 2151jquery-autocomplete 自动填 ... -
一个将10亿以内的阿拉伯数字转成汉字大写形式通用类
2010-07-23 21:58 1968package com /** * 将10亿以内的阿拉伯数字 ... -
关于Struts1&2 Spring Hibernate 三大框架学习综合整理
2010-07-23 21:49 1116关于三大框架struts1&2/h ... -
关于对刚刚进入软件行业编程人员的一些建议
2010-07-23 21:38 995作为一个软件开发编程人员,其至少要必备1本或者2~3本Ja ...
相关推荐
基于J2EE的Web Service分布式应用研究涉及的技术领域非常广泛,从文档中提取的知识点包含了J2EE技术、Web Service技术、分布式系统设计、服务架构、以及异步与同步服务模式等多个方面。 1. J2EE技术:J2EE(Java 2 ...
WebService作为一种基于XML的分布式计算平台,它允许应用程序通过网络进行跨平台的交互。Web Service在B/S模型中扮演着重要的角色,因其基于标准的协议(如HTTP, SOAP, WSDL, UDDI),易于实现不同系统的集成。Web ...
从提供的文件信息来看,这篇文章探讨了基于OSGi(Open Service Gateway initiative)的分布式Web应用结构,其内容主要集中在分布式系统架构、资源分配优化以及OSGi技术在Web应用部署方面的应用。 知识点一:OSGi...
Java分布式应用是现代企业级软件开发中的重要组成部分...以上知识点构成了Java分布式应用的基础,涵盖通信、服务架构、内存管理、并发编程、性能优化和系统设计等多个层面,是构建大型、高可用、可扩展系统的必备技能。
文档中的知识可以作为开发者构建基于Tuscany SCA的分布式应用的参考资料,并可能包含行业专家的见解和建议。这有助于开发者更好地理解分布式系统的复杂性,并在实践中提高开发效率和系统稳定性。
以上知识点涵盖了Java分布式应用程序设计的核心概念和技术。通过深入理解和熟练运用这些技术,开发者可以构建出强大且可靠的分布式系统。压缩包文件"soft.studa.com Java 分布式应用程序设计"可能包含了实现这些技术...
Java Web Service 是一种基于 XML 的分布式系统架构,它使得不同的系统和应用程序可以通过标准的协议和数据格式进行通信和交互。下面是 Java Web Service 的总结,涵盖了 Web Service 的原理、技术支持、 AXIS 实现...
综上所述,基于Web Service的知识库和CAD集成研究是一个涉及CAD技术应用、建模分析、分布式系统集成等多个IT领域的重要课题。这项研究不仅为CAD系统和知识库之间的集成提供了新的思路和方法,也为现代制造业中复杂...
分布式Java基础与实践是开发者进入大型系统开发领域的重要学习内容,尤其对于初学者而言,掌握这一领域的基础知识至关重要。本文将围绕分布式系统、Java在其中的角色以及实践应用进行深入讲解。 首先,分布式系统是...
【Eclipse下基于Axis2的Web Service平台搭建与使用】涉及多个IT领域的知识点,以下是详细的说明: 1. **Web Service**:Web Service是一种基于网络的、分布式的模块化组件,它提供了一种标准的方式,使得不同的应用...
1. **Java分布式计算基础**:Java为分布式计算提供了强大的支持,包括RMI(Remote Method Invocation)和JMS(Java Message Service),它们允许在不同计算机上的对象之间进行交互。RMI允许一个对象调用另一个在网络...
1. 分布式Java应用基础 分布式Java应用的核心在于组件之间的远程方法调用(Remote Procedure Call, RPC)。Java RMI(Remote Method Invocation)是Java提供的一种原生的RPC机制,允许对象在不同的JVM之间进行交互...
以上就是分布式Java应用基础与实践中涉及的关键知识点,这些内容将帮助开发者构建出强大的、可扩展的分布式系统,应对不断变化的业务需求。通过深入理解和实践,开发者能够提升其在分布式系统设计和实现方面的专业...
以上这些知识点详细地阐述了基于SOA的柔性分布式仿真框架设计的理论基础、技术应用、系统架构及其实现方法,为读者提供了一个关于如何构建适应性强、跨地域、跨平台的分布式仿真系统的深刻理解。
在《实战Delphi6/Kylix2/SOAP/Web Service程序设计篇》这本书中,作者李维精心编撰了一套系统而全面的教程,针对的...虽然现在技术迭代迅速,但理解这些基础知识对于理解现代Web开发的历史演变和底层原理仍然具有价值。
PB11(PowerBuilder 11)是一款由Sybase公司推出的可视化编程工具,主要...通过深入学习这些内容,开发者可以掌握使用PB11和Web Service构建分布式三层应用的核心技术和实践策略,从而提升其在企业级应用开发中的能力。
Web Service是一种基于互联网的、平台无关的、可互操作的分布式计算模式,它允许不同系统之间的应用程序进行通信和数据交换。在软件设计师的学习路径中,理解并掌握Web Service的原理、模型以及实际应用是至关重要的...
XML Web Service 开发是构建分布式应用程序的关键技术,它允许不同平台和系统间的应用程序无缝通信。在互联网上,Web 服务利用标准技术,如HTTP和XML,使得任何客户端,包括前端应用、浏览器、移动设备和PDA等,都能...
分布式JAVA应用基础与实践是Java开发领域中的一个重要主题,它涉及到如何通过网络连接将多个独立的Java应用程序协同工作,以实现更大规模、更高性能、更可靠的服务。在本教程中,我们将深入探讨Java在分布式环境中的...