应网友需求,写一篇关于WebService的博客
1.1 WebService概述
1.1.1 WebService简介
WebService是一种跨编程语言和跨操作系统平台的远程调用技术。
所谓跨编程语言和跨操作平台,就是说服务端程序采用java编写,客户端程序则可以采用其他编程语言编写,反之亦然!跨操作系统平台则是指服务端程序和客户端程序可以在不同的操作系统上运行。
所谓远程调用,就是一台计算机a上的一个程序可以调用到另外一台计算机b上的一个对象的方法,譬如,银联提供给商场的pos刷卡系统,商场的POS机转账调用的转账方法的代码其实是跑在银行服务器上。再比如,amazon,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以webservice服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能,这样扩展了自己系统的市场占有率,往大的概念上吹,就是所谓的SOA应用。
从表面上看,WebService就是一个应用程序向外界暴露出一个能通过Web进行调用的API,也就是说能用编程的方法通过Web来调用这个应用程序。我们把调用这个WebService的应用程序叫做客户端,而把提供这个WebService的应用程序叫做服务端。从深层次看,WebService是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义了应用程序如何在Web上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。
WebService平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,WebService平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。Web service平台必须提供一种标准来描述Web service,让客户可以得到足够的信息来调用这个Web service。最后,我们还必须有一种方法来对这个Web service进行远程调用,这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性,这种RPC协议还必须与平台和编程语言无关。
1.1.2 两种传输协议
JAX-WS全称是JavaTM API forXML-BasedWebServices
是面向消息的,每次请求的时候指定了请求的方法。
传输数据为xml格式,基于soap协议实现
JAX-RS :全称是 JavaTM APIforRESTful Web Services
是面向资源的。后则将网络上的东西当做一种资源,每次请求都是对该资源进行操作,比如对资源的增删查改。
传输数据为xml或者json格式,基于http协议实现
1.1.3 WebService实现原理
Web服务有两层含义:1、是指封装成单个实体并发布到网络上的功能集合体;2、是指功能集合体被调用后所提供的服务。简单地讲,Web服务是一个URL资源,客户端可以通过编程方式请求得到它的服务,而不需要知道所请求的服务是怎样实现的,这一点与传统的分布式组件对象模型不同。
Web服务的体系结构是基于Web服务提供者、Web服务请求者、Web服务中介者三个角色和发布、发现、绑定三个动作构建的。简单地说,Web服务提供者就是Web服务的拥有者,它耐心等待为其他服务和用户提供自己已有的功能;Web服务请求者就是Web服务功能的使用者,它利用SOAP消息向Web服务提供者发送请求以获得服务;Web服务中介者的作用是把一个Web服务请求者与合适的Web服务提供者联系在一起,它充当管理者的角色,一般是UDDI。这三个角色是根据逻辑关系划分的,在实际应用中,角色之间很可能有交叉:一个Web服务既可以是Web服务提供者,也可以是Web服务请求者,或者二者兼而有之。显示了Web服务角色之间的关系:其中,“发布”是为了让用户或其他服务知道某个Web服务的存在和相关信息;“查找(发现)”是为了找到合适的Web服务;“绑定”则是在提供者与请求者之间建立某种联系。
Webservice的体系结构
实现一个完整的Web服务包括以下步骤:
◆ Web服务提供者设计实现Web服务,并将调试正确后的Web服务通过Web服务中介者发布,并在UDDI注册中心注册; (发布)
◆ Web服务请求者向Web服务中介者请求特定的服务,中介者根据请求查询UDDI注册中心,为请求者寻找满足请求的服务; (发现)
◆ Web服务中介者向Web服务请求者返回满足条件的Web服务描述信息,该描述信息用WSDL写成,各种支持Web服务的机器都能阅读;(发现)
◆ 利用从Web服务中介者返回的描述信息生成相应的SOAP消息,发送给Web服务提供者,以实现Web服务的调用;(绑定)
◆ Web服务提供者按SOAP消息执行相应的Web服务,并将服务结果返回给Web服务请求者。(绑定)
1.1.4 开发环境搭建
第一步、依赖导入
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.colobu</groupId>
<artifactId>fastjson-jaxrs-json-provider</artifactId>
<version>0.3.1</version>
<scope>compile</scope>
</dependency>
第二步、编写配置文件
web.xml
<servlet>
<servlet-name>CXFService</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFService</servlet-name>
<!--WebService路径必须和struts2的拦截路径区分开来,不然会优先被struts2拦截-->
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
application-webService.xml
<jaxrs:server id="customerService" address="/customerService">
<jaxrs:serviceBeans>
<bean class="cn.itcast.crm.service.impl.CustomerServiceImpl"/>
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxrs:outInterceptors>
</jaxrs:server>
CustomerService
publicinterface CustomerService {
// 查询所有未关联客户列表
@Path("/findNoAssociationCustomers")
@GET
@Produces({ "application/xml", "application/json" })
public List<Customer> findNoAssociationCustomers();
}
最终对外访问路径:域名(本机IP)+项目名+拦截路径+服务类地址+访问地址
1.1.5 WebService应用场景
1.跨防火墙的通信
如果应用程序有成千上万的用户,而且分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。因为客户端和服务器之间通常会有防火墙或者代理服务器。在这种情况下,使用DCOM就不是那么简单,通常也不便于把客户端程序发布到数量如此庞大的每一个用户手中。传统的做法是,选择用浏览器作为客户端,写下一大堆JSP页面,把应用程序的中间层暴露给最终用户。这样做的结果是开发难度大,程序很难维护。
如果中间层组件换成WebService的话,就可以从用户界面直接调用中间层组件,从而省掉建立JSP页面的那一步。要调用WebService,可以直接使用SOAP这样的客户端,也可以使用自己开发的SOAP客户端,然后把它和应用程序连接起来。不仅缩短了开发周期,还减少了代码复杂度,并能够增强应用程序的可维护性。同时,应用程序也不再需要在每次调用中间层组件时,都跳转到相应的“结果页”。
2.应用程序集成
企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的、在不同平台上运行的各种程序集成起来,而这种集成将花费很大的开发力量。应用程序经常需要从运行在IBM主机上的程序中获取数据;或者把数据发送到主机或UNIX应用程序中去。即使在同一个平台上,不同软件厂商生产的各种软件也常常需要集成起来。通过WebService,应用程序可以用标准的方法把功能和数据“暴露”出来,供其它应用程序使用。
3. B2B的集成
用WebService集成应用程序,可以使公司内部的商务处理更加自动化。但当交易跨越供应商和客户、突破公司的界限时会怎么样呢?跨公司的商务交易集成通常叫做B2B集成。WebService是B2B集成成功的关键。通过WebService,公司可以把关键的商务应用“暴露”给指定的供应商和客户。例如,把电子下单系统和电子发票系统“暴露”出来,客户就可以以电子的方式发送订单,供应商则可以以电子的方式发送原料采购发票。当然,这并不是一个新的概念,EDI(电子文档交换)早就是这样了。但是,WebService的实现要比EDI简单得多,而且WebService运行在Internet上,在世界任何地方都可轻易实现,其运行成本就相对较低。不过,WebService并不像EDI那样,是文档交换或B2B集成的完整解决方案。WebService只是B2B集成的一个关键部分,还需要许多其它的部分才能实现集成。
4.软件和数据重用
软件重用是一个很大的主题,重用的形式很多,重用的程度有大有小。最基本的形式是源代码模块或者类一级的重用,另一种形式是二进制形式的组件重用。当前,像表格控件或用户界面控件这样的可重用软件组件,在市场上都占有很大的份额。但这类软件的重用有一个很大的限制,就是重用仅限于代码,数据不能重用。原因在于,发布组件甚至源代码都比较容易,但要发布数据就没那么容易,除非是不会经常变化的静态数据。
2.2 常用注解和方法
2.2.1 服务提供端
Annotation |
作用 |
说明 |
@GET |
查询请求 |
相当于数据库的查询数据操作 |
@POST |
插入请求 |
相当于数据库的插入数据操作 |
@PUT |
更新请求 |
相当于数据库的更新数据操作 |
@DELETE |
删除请求 |
相当于数据的删除数据操作 |
@Path |
uri路径 |
定义资源的访问路径,client通过这个路径访问资源。比如:@Path("user/{name}") (name为传入参数) |
@Produces |
指定返回MIME格式 |
资源按照那种数据格式返回,可取的值有:MediaType.APPLICATION_XXX。比如:@Produces(MediaType.APPLICATION_XML) |
@Consumes |
接受指定的MIME格式 |
只有符合这个参数设置的请求再能访问到这个资源。比如@Consumes("application/x-www-form-urlencoded") |
@PathParam |
uri路径参数 |
写在方法的参数中,获得请求路径参数。比如:@PathParam("username") String userName |
@QueryParam |
uri路径请求参数 |
写在方法的参数中,获得请求路径附带的参数。比如:@QueryParam("desc") String desc |
@DefaultValue |
设置@QueryParam参数的默认值 |
如果@QueryParam没有接收到值,就使用默认值。比如:@DefaultValue("description") @QueryParam("desc") String desc |
@FormParam |
form传递的参数 |
接受form传递过来的参数。比如:@FormParam("name") String userName |
@BeanParam |
通过Bena的形式传递参数 |
接受client传递的bean类型的参数,同时这个bean可以在属性上配置@FormParam用以解决client的属性名称和bean的属性名称不一致的问题。比如:@BeanParam User user |
@Context |
获得一些系统环境信息 |
通过@Context可以获得以下信息:UriInfo、ServletConfig、ServletContext、HttpServletRequest、HttpServletResponse和HttpHeaders等 |
@XmlRootElement |
将bean转换为xml |
如果要讲bean以xml或json的格式返回,必须要这个注解。比如: @XmlRootElement public class User{...} |
@XmlSeeAlso |
注明实际类型 |
返回泛型时必须注明是实际类型 |
@XmlElement |
|
|
2.2.2 服务接受端
针对查询操作
Customer customer = WebClient.create("http://localhost:8082/crm_management/services"
+"/customerService/findByTelephone/" + model.getTelephone()).accept(MediaType.APPLICATION_JSON)
.get(Customer.class);
accept()接受参数的样式 get()获取对象类型
针对修改操作
WebClient.create("http://localhost:8082/crm_management/services"
+ "/customerService/updateType/" + model.getTelephone()).put(null);
pull()传入的对象实例
针对保存操作
WebClient.create("http://localhost:8082/crm_management/services/customerService/save")
.type(MediaType.APPLICATION_JSON).post(customer);
type()传入的参数格式 post()传入的实例对象