- 浏览: 122352 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
ze_nana:
那楼主去哪个行业了?
怀念曾经的日子 -
誓言无声:
...
我的90后学生的一篇检查 -
lvwenwen:
不错,楼主要是能上传能跑的工程就更好了,楼主加油!
JMS(Java Massage Service)与MDB(Massage Driver Bean) -
lvff1314:
楼主的爬虫是自己用socket写的还是用的开源框架啊,可否跟大 ...
《说说做网站的事》我朋友写的关于自己开发一个网站的经验帖 -
MVC2008MVC:
感觉自己玩玩还行
《说说做网站的事》我朋友写的关于自己开发一个网站的经验帖
Web Service简介及开发实例
作者:岳乡成
本文档实例Dome基于的技术是:JSF + Jboss-seam-2.1.1.GA. + Jboss 4.2.3 GA + EJB 3.0 + Jboss ESB + My-SQL-5.0.8 + JDK 1.6。由于实例工程太大,不能放博客上,如有需要联系我,MSN:xiangcheng.yue@163.com。
QQ号码:827650367。
一、 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的两种方法,因为能力有限,所以写的不好,仅供参考。希望对大家有帮助,谢谢。
作者:岳乡成
本文档实例Dome基于的技术是:JSF + Jboss-seam-2.1.1.GA. + Jboss 4.2.3 GA + EJB 3.0 + Jboss ESB + My-SQL-5.0.8 + JDK 1.6。由于实例工程太大,不能放博客上,如有需要联系我,MSN:xiangcheng.yue@163.com。
QQ号码:827650367。
一、 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的两种方法,因为能力有限,所以写的不好,仅供参考。希望对大家有帮助,谢谢。
- Web_Service简介及开发实例.rar (60.6 KB)
- 下载次数: 307
评论
4 楼
liuzm
2010-06-12
呵呵,学习了
3 楼
rickyboy
2010-04-26
请教一下
ejb 发布的服务端
是否可以处理soap报头的部分
ejb 发布的服务端
是否可以处理soap报头的部分
2 楼
岳乡成
2010-01-07
不会有一本书把你上面所要学的东西囊括的,你想要学的东西是一个庞大的相关体系,要翻阅好的书,而这些书一般只会侧重于某一方面。jboss ESB除了官方文档外,中文的权威参考资料非常少,英文倒是有几本,但要你的英文水平达到可以看懂的程度。别着急,要写好你想要学的东西要花费一段时间,而且要求你的知识积累到一定程度了。
1 楼
tkivdrip
2010-01-06
你好 我最近一直在学习 JBOSS ESB SOA WebService 但是在网上找了好久也没有什么全的资料 感觉力不从心啊
相关推荐
### Web Service应用实例详解 #### 一、IIS安装与配置 在开发Web Service之前,首先需要确保服务器上已正确安装并配置了Internet Information Services (IIS)。无论是Windows Server 2003还是Windows XP,IIS都是...
本实例将详细讲解如何使用Delphi创建Web Service接口以及在客户端进行调用。 1. **创建Web Service接口** 在Delphi中,我们可以使用内置的`WebBroker`组件来创建Web Service。首先,创建一个新的VCL Forms应用程序...
### Axis开发Web Service实例详解 #### 一、概述 在探讨如何使用Apache Axis来开发Web Service之前,我们首先需要了解一些基本概念。 **Web Service**是一种标准的技术框架,用于实现不同平台之间的应用通信。它...
根据给出的内容,我们将详细解释Java Web服务规范、开发工具以及服务端和客户端的开发流程。 ### Java Web服务规范 Java Web服务规范主要分为以下三种: 1. **JAXM&SAAJ**:JAXM(Java API for XML Messaging)是...
在"Web Service 开发实例 文档 1.4 wsdd client 完整"这个主题中,我们可以深入学习以下几个关键知识点: 1. **Web Service描述语言(WSDL)**: WSDL(Web Services Description Language)是XML格式的规范,用于...
【ASP.NET与Web Service实例剖析】是一场技术讲座或教程,专注于讲解如何使用ASP.NET技术和Web Service进行实际项目开发。ASP.NET是微软推出的用于构建Web应用程序的开发框架,而Web Service则是一种基于XML的通信...
在"Web Service学习-CXF开发Web Service实例demo(一)"中,我们将专注于SOAP Web Service的实现。以下是一些关键步骤: 1. **创建服务接口**:首先,你需要定义一个Java接口,这个接口会成为你的Web Service接口。...
Web服务的核心概念是SOA(Service-Oriented Architecture,面向服务架构),它提倡将业务功能作为独立的服务,这些服务可以通过标准协议进行交互。HTTP(超文本传输协议)通常作为基础传输层,因为其广泛支持和无...
二、PB11中的Web Service开发 1. **创建Web Service客户端**:PB11提供了一个直观的向导,帮助开发者通过WSDL文件创建Web Service代理类。这使得开发者能够轻松地调用远程Web Service的方法,如同调用本地对象一样。...
本教程旨在为初学者提供一个深入理解XML Web Service开发的基础,帮助他们掌握这一核心技术。 一、XML Web Service基础 XML Web Service的核心在于XML,它是一种通用的数据表示语言,具有自我描述性和平台无关性。...
C# Web Service 开发实例:WeatherWinApp(天气预报Windows版) 介绍C# Web Service快速开发入门实例。 Visual Studio 2010环境中自动添加Web引用代码,制作自己的天气预报软件。
《T100 Web Service 接口开发v1.5版》 在现代信息技术领域,Web Service接口开发扮演着至关重要的角色,它使得不同系统之间的数据交换和功能调用变得简单而高效。本文将深入探讨T100 Web Service接口开发的最新版本...
XML Web Service是C#编程中一个重要的概念,它允许不同平台和语言的系统之间进行数据交换,实现分布式应用程序的开发。在Visual Studio 2005中,XML Web Service的创建和使用相对简单,为开发者提供了高效的工作流程...
这个实例代码是Web开发领域的一个基础示例,它展示了服务端和客户端之间的数据交换。 首先,我们需要理解什么是Web Service。Web Service是一种基于互联网的、平台独立的软件组件,它能够通过标准协议(如SOAP或...
Spring Web Service是Spring社区基于Spring提供的一个关注于创建”文档驱动”的Web Service的模块, 它的主要目标是方便基于”契约优先”(Contract-First)的SOAP服务的开发. 好像没有多少人讨论, 大多数的话题都是...
ASP.NET和Web Service是开发基于Web应用程序的重要技术。...通过深入学习和实践"ASP .NET 与 Web Service 实例剖析",开发者可以提升在Web应用程序开发中的技能,理解如何在不同的系统之间创建可靠的数据交换通道。
### Cognos Web Service 开发(.NET 实例) #### 引言 本文档将详细介绍如何使用 Microsoft Visual Studio .NET 进行 Cognos Web Services 的开发。通过一个简单的 Visual Basic 应用程序来演示 Cognos Web ...
Web服务是一种基于网络的、平台无关的交互方式,允许不同系统之间交换数据和服务。本教程主要针对初学者,深入浅出地...本教程通过实例演示了Web服务的开发流程,对于初学者理解Web服务的概念和技术细节非常有帮助。