资源描述
第 14 章 WebService 与 SOA 的实现WebService 与 SOA 是现在 java 领域非常热门的内容。本章将对 EJB3.0 来实现 WebService 与 SOA 进行介绍。14.1WebService 的概念WebService 是一个新的概念,它并不是微软首先提出的,但是微软的 dotnet 战略让它 最广泛的发挥它的潜能。WebService最早被应用在Sun等对网络先知先觉的平台上。而 J2EE是最早的成功开发WebService的平台,它的理念就是在网上最广泛的传播、使用, 成为一种真正的服务。简单一句话来说,Web Service就是为了使原来各孤立的站点之间的 信息能够相互通信、共享而提出的一种接口。Web Service所使用的是Internet上统一、开放的标准,女口 HTTP、XML、SOAP (简 单对象访问协议)、 WSDL 等。1.XML 和 XSD可扩展的标记语言XML是Web Service平台中表示数据的基本格式。除了易于 建立和易于分析外,XML主要的优点在于它既与平台无 关,又与厂商无关。XML是 由万维网协会(W3C)创建,W3C制定的XML SchemaXSD 定义了一套标准的数据类 型,并给出了一种语言来扩展这 套数据类型。Web Service平台是用XSD来作为数据 类型系统的。当你用某种语言如VB.NET或C#来构造一个Web Service时,为了 符合Web Service标准,所有你使用的数据类型都必须被转换为XSD类型。如想让它 使用在不同平台和不同软件的不同组织间传递,还需要用某种东 西将它包装起来。这 种东西就是一种协议,如 SOAP。2.SOAPSOAP 即简单对象访问协议 (Simple Object Access Protocol) ,它是用于交换 XML 编码信息的轻量级协议。它有三个主要方面:XML-envelope为描述信息内容和如何 处理内容定义了框架,将程序对象编码成为XML对象的规则,执行远程过程调用(RPC) 的 约定。SOAP可以运行在任何其他传输协议上。例如,你可以使用SMTP,即因特 网电子邮件协议来传递 SOAP 消息,这可是很有诱惑力的。在传输层之间 的头是不 同的,但XML有效负载保持相同。Web Service希望实现不同的系统之间能够用“软件 -软件对话”的方式相互调用,打破了软件应用、网站和各种设备之间的格格不入的状 态,实现“基于Web无缝集成”的目标。3. WSDLWeb Service 描述语言 WSDL 就是用机器能阅读的方式提供的一个正式描述文 档而基于XML的语言,用于描述Web Service及其函数、参数和返回值。因为是基于 XML的,所以WSDL既是机器可阅读的,又是人可阅读的。4. UDDIUDDI的目的是为电子商务建立标准;UDDI是一套基于Web的、分布式的、为 Web Service 提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身 提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。5. 远程过程调用 RPC 与消息传递Web Service本身其实是在实现应用程序间的通信。我们现在有两种应用程序通信 的方法:RPC远程过程调用 和消息传递。使用RPC的时候,客户端的概念是调用 服务器上的远程过程,通常方式为实例化一个远程对象并调用其方法和属性。RPC系 统试图达到一种位置上的透明性:服务器暴露出 远程对象的接口,而客户端就好像在 本地使用的这些对象的接口一样,这样就隐藏了底层的信息,客户端也就根本不需要 知道对象是在哪台机器。使用Web Service具有下面的一些特点:优势:I. 跨平台。 WebService 的主要目标就是跨平台的可互操作性。为了达到这一目标,WebService完全基于XML (可扩展标记语言)、XSD (XMLSchema)等独立于平 台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新平台。II. 并且SOAP协议是基于XML和HTTP这些业界的标准的,得到了所有的重要公 司的支持。III. 由于使用了 SOAP,数据是以ASCII文本的方式而非二进制传输,调试很方便; 并且由于这样,它的数据容易通过防火墙,不需要防火墙为了程序而单独开一个 “漏洞”。IV 此外,WebService实现的技术难度要比CORBA和DCOM小得多。V 要实现B2B集成,EDI比较完善与比较复杂;而用WebService则可以低成本的实 现,小公司也可以用上。VI.在C/S的程序中,WebService可以实现网页无整体刷新的与服务器打交道并取数。 缺点:I. WebService使用了 XML对数据封装,会造成大量的数据要在网络中传输。II. WebService 规范没有规定任何与实现相关的细节,包括对象模型、编程语言,这 一点,它不如 CORBA。了解了 WebService 的概念和原理后,下面我们来看看如何用 ejb3.0 实现 WebService。14.2 WebService+Ejb 3.0 的实现本节使用 EJB 3.0 实现一个 webService 登录的例子。下面我们创建一个工程叫 EmployeeManager 。加入用到的 EJB 3.0 的 jar 包。我们先创建服务器端的实体Bean,这和创建普通的Ejb3.0实体bean是一样的: package com.ascent.ejb.po;import java.io.Serializable;import javax.ejb.Remote;import javax.ejb.Stateless;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;SuppressWarnings(serial)EntityTable(name = usr)public class User implements Serializableprivate Integer id;private String name;private String password;private String description;IdGeneratedValuepublic Integer getId()return id;public void setId(Integer id)this.id = id;Column(name = name, nullable = false)public String getName()return name;public void setName(String name)this.name = name;Column(name = password, nullable = false)public String getPassword()return password;public void setPassword(String password)this.password = password;Column(name = description, nullable = true, length = 100) public String getDescription()return description;public void setDescription(String description)this.description = description;接着创建远程接口:package com.ascent.webservice.bean;import java.rmi.Remote;import javax.jws.WebMethod;import javax.jws.WebService;import javax.jws.soap.SOAPBinding;import javax.jws.soap.SOAPBinding.Style;WebServiceSOAPBinding(style=Style.RPC)public interface LoginDao extends Remote WebMethodpublic boolean isLogin(String name, String password);在 LoginDao 类中要注意的是 Remote 接口是要实现的,SOAPBinding(style=Style.RPC), Soap 的绑定方式也是需要的,不然在客户端是找不到 LoginDao 。下面创建会话 bean:package com.ascent.webservice.bean;import java.util.List;import javax.ejb.Stateful;import javax.ejb.Stateless;import javax.jws.WebService;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.persistence.Query;StatelessWebService(endpointInterface = com.ascent.webservice.bean.LoginDao)public class LoginDaoBeanPersistenceContextprotected EntityManager em;/ the manager of entitypublic boolean isLogin(String name, String password)/ define query sentenceStringBuffer hql = new StringBuffer();hql.append(from User u where u.name= + name + );hql.append( and u.password= + password + );/ create the queryQuery query = em.createQuery(hql.toString();List queryList = query.getResultList();/ if the result is nullif (queryList.size() = 0)return false;/ if the users length greater 1if (queryList.size() 1)return false;/ return single userreturn true; 至此服务器端的类是建好了,这里又两个问题,需要说明一下A 两个类的方法中都没有抛出异常,可不可以抛出呢 ? 可以。但到实现SOA 的时候会有一些问题,就是异常在经 axis 通过 WSDL2Java 生成后, 在程序运行时有可能会出现找不到的情形。所以本文为了让大家在仿照这个 例子时都能成功,所以也就抛弃了异常的抛出。B 两个类的方法的返回值是基本类型,而不是自定义类型,为什么会这样 呢,自定义类型可以不可以呢,可以。现在我 们的 webservice 的服务器 端就已经创建好 了,我们把服务 器端的三个类和 persistence.xml 文件一起打包部署到 jboss 服务器里。包名是: empdEjb。下面我们来创建客户端:package com.ascent.webservice.client;import .URL;import javax.xml.namespace.QName;import javax.xml.rpc.Service;import javax.xml.rpc.ServiceFactory;import com.ascent.webservice.bean.LoginDao;public class LoginClientpublic static void main(String args) throws ExceptionString userName =lxl;String password = lxl;URL url = new URL(http:/localhost:8080/empdEjb/LoginDaoBean?wsdl);QName qname =new QName(ServiceFactory factory = ServiceFactory.newInstance();Service service = factory.createService(url, qname);LoginDao loginDao = (LoginDao) service.getPort(LoginDao.class);boolean isExists = loginDao.isLogin(userName, password);if(isExists)System.out.println(hello + userName);elseSystem.out.println(sorry + userName + , you are not user in the system!);把服务器端发布出去以后,服务器端会自动发布一个 webService ,并且生成并发布一 个 WSDL 文件,通过访问 http:/localhost:8080/empdEjb/LoginDaoBean?wsdl 这个网址是可 以找到的。 和 LoginDaoService 字符串,在客户端程 序当中出现了上面两个字符串,它们在你生成的 wsdl 文件中有详细的描述。在地址栏里 输入 http:/localhost:8080/empdEjb/LoginDaoBean?wsdl,就可以看到 wsdl 文件了。这里你 所需要做的是按照你自己的情况编写你自己的客户端程序。启动服务器后,在机子上运行 客户端程序就可以了。当然你也可以去编写自己的 jsp 客户端去调用它。 wsdl 文件的内容 如下:definitions name=LoginDaoServicetargetNamespace= 这样一个 WebService+Ejb 3.0 的例子就实现了。14.3 SOA 的概念SOA ( Service Oriented Architecture ), 是当前比较热门的话题,是一种服务与技术分离的实 现,从而达到服务可重用性的一种思想14.4 SOA 的实现本例还是基于前两个例子的基础上的,要保证上面的例子是能正常运行的。14.4.1WSDL2Java从名字上可以看出,是把 wsdl 转化为 java 的. 在上面的例子中我们在服务 器端生成了一个wsdl文件,现在要做的就是你把那个wsdl文件给别人或者别 的公司,让他们根据wsdl中所描述的你所提供的服务,去开发一个应用,来访 问你所提供的接口。拿到这个WSDL文件后要做什么呢,to java。我们来看看 怎么 to java。这里,在原来的 EmployeeManager 工程下面建一个 wsdl 文件夹,将它放在 下面,然后所要做的准备工作是,把包括axis在内的几个jar包找到,设置在你 的 classpath 里面。然后在命令行下运行 WSDL2Java。哪几个 jar 包?C:axis-1_4libaxis.jar;C:axis-1_4libaxis-ant.jar;C:axis-1_4libcommons-dis covery-0.2.jar;C:axis-1_4libcommons-logging-1.0.4.jar;C:axis-1_4libjaxrpc.jar;C:axis-1_4liblog4j-1.2.8.jar;C:axis-1_4libsaaj.jar;C:axis-1_4libwsdl4j-1.5.1.ja r;E:jboss-4.0.5serverdefaultlibactivation.jar;E:jboss-4.0.5serverdefaultlibmail.jar这是我 classpath 里面所设置的几个 jar 包,后面两个可以不需要,第二个 也可以不需要,后俩个只是保证运行的时候没有警告。1 将 LoginDaoBean.wsdl 放在 wsdl 文件夹下面。 E:workspaceEmployeeManagerwsdl2 在命令行下进入 E:workspaceEmployeeManagerwsdl3 执行 java org.apache.axis.wsdl.WSDL2Java LoginDaoBean.wsdl 这个时候,你会发现在 wsdl 文件夹下面生成了一个目录,它里面包含了几 个 java 类。LoginDao.java, LoginDaoBindingStub.java , LoginDaoService.java , LoginDaoServiceLocator.java14.4.2 SOA 的实现本节是一个以SOA+struts实现登录的例子。新建一个web工程,EmployeeWebService, 然后将上面生成的几个类放入你的 src 目录下面,是放整个目录,别只放几个类进去 . 构 建 struts 资源。创建 struts 的过程就不在这里细说了。创建的 action 内容如下:package com.ascent.webservice.struts.action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import mons.logging.Log;import mons.logging.LogFactory;import org.apache.struts.action.Action;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionMessage;import org.apache.struts.action.ActionMessages;import com.ascent.webservice.struts.form.LoginForm;import com.ascent.webservice.bean.jaws.LoginDao;import com.ascent.webservice.bean.jaws.LoginDaoServiceLocator;public class LoginAction extends Actionpublic ActionForward execute(ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response)throws Exception LoginForm loginForm = (LoginForm) form;String userName = loginForm.getLoginName();String password = loginForm.getPassword();LoginDaoServiceLocator loginDaoServiceLocator = new LoginDaoServiceLocator();LoginDao loginDao= loginDaoServiceLocator.getLoginDaoPort();boolean isExists = loginDao.isLogin(userName, password);if(isExists)System.out.println(hello + userName);HttpSession session = request.getSession();session.setAttribute(loginName, loginForm.getLoginName();return mapping.findForward(success);elseSystem.out.println(sorry + userName + , you are not user in the system!);ActionMessages messages = new ActionMessages();messages.add(login,new ActionMessage(error.login.jsp.loginName.exists); this.saveErrors(request, messages);return mapping.getInputForward();这里用至U的 LoginDaoServiceLocator 类和 getLoginDaoPort()方法就是使用 WSDL2Java命令把wsdl文件生成的类。现在就可以打包成叫employee的 war 文件, 运行它。至此,你便可以在浏览器中输入 http:/localhost:8080/employee /login.jsp,运行你这个 SOA 的应用了。如果是把服务器端部署至别的机器上,只要把 localhost 改为相应的 ip 就可以 了。
展开阅读全文