webservice是跨编程语言和跨平台的远程调用技术。常见的远程调用技术还有RMI,因为webservice跨平台和跨编程语言,因此应用更广泛,但性能略低。
远程调用:一台计算机a上的一个程序可以调用另一台计算机b上的一个对象的方法。
关于Java webService框架,主要有AXIS、XFire、CXF,还有Java自带的JAX-WS(必须JDK6以上环境)。
SOAP:是在分布式的环境中交换信息的简单协议,以XML作为数据传送的方式。
SOAP=RPC+HTTP+XML
SOAP RPC的工作原理:类似于web的请求/响应方式,不同之处在于web客户和web服务器之间传输的是HTML数据。在SOAP RPC模式中,SOAP客户(程序)和SOAP服务之间传输的是符合SOAP规范的XML数据。(XML中说明调用远程服务对象的哪个方法、传递的参数是什么,以及服务对象的返回结果是什么。)
WSDL:webservice客户端要调用一个webservice服务,首先要知道这个服务的地址在哪,以及这个服务有什么方法可以调用。因此webservice服务端首先要通过一个WSDL文件来说明有什么服务可以对外调用,服务是什么,有哪些方法,方法接受的参数是什么,返回值是什么。
WSDL文件保存在服务端,可以通过url地址访问到。客户端要调用一个webservice服务之前,要知道该服务的WSDL文件的地址。webservice服务提供者可以通过两种方式暴露它的WSDL文件地址:
a、注册到UDDI服务器,以便被人查找;
b、直接告诉客户端调用者;
要访问一个远程的webservice,有两种方法:
a、通过SOAP协议;
b、通过REST的方式;
1、AXIS是apache软件组织对SOAP规范的实现。
SOAP客户程序——>AXIS API—RPC请求—>AXIS web应用(SOAP服务),此web应用可以放在Tomcat容器中。
在AXIS上创建和发布基于RPC的SOAP服务步骤:
a、创建实现SOAP服务的java类;
b、创建SOAP服务的发布描述文件;
c、通过AXIS的AdminClient客户程序发布SOAP服务;
一个web容器中的web应用———远程访问———>另一个web容器中的AXIS应用(SOAP服务)
2、web服务开源框架XFire
XFire是下一代的java soap开源框架。XFire提供了方便的API,使用这些API可以开发面向服务(SOA)的程序。
XFire是codehaus组织一个web服务开源框架项目,官方主页为http://xfire.codehaus.org.
主要特性包括:
a、支持多个重要的webservice标准,包括SOAP、WSDL等。
b、支持JSR181,可以通过JDK5中的注解配置web服务。
c、支持基于HTTP、JMS等多种协议访问web服务。
d、支持spring、Pico等多种容器。
e、支持客户端和服务器代码生成。
XFire在1.2.6版本后与Celtix合并成为apache的CXF项目,主页为http://cxf.apache.org。
到XFire主页下载xfire-distribution-1.2.6.zip。解压后得到目录结构为:
api目录:是XFire框架中所有类对应的Java Doc文档。
lib目录:XFire运行所依赖的jar包。
manual目录: 包含有XFire框架的帮助文档,可以从中学习更多运用XFire框架实现SOA的知识和技巧。
xFire-all-1.2.6.jar:XFire框架的jar包,包括了全部的模块。
其中lib目录中的jar包和xFire-all-1.2.6.jar是XFire运行所必须的类库。
(1)在Myeclipse中发布web服务
a、新建一个web工程,导入XFire运行所必须的jar包。如:XFireDemo
b、创建服务的接口及实现类。
c、在web .xml文件中,配置XFire的servlet。
如:
定义在web.xml中的XFireServlet负责提供web服务,且提供WSDL。
d、在工程下,新建WebServices/services.xml文件。(该配置文件定义了一个web服务)
如:
该配置文件为XFire发布服务的配置文件,当请求服务时,XFire会根据这个配置文件解析对应的服务。
e、将此web工程发布到Tomcat中。
(2)在Myeclipse中调用web服务
当web服务发布后,在客户端有多种方式调用。如Myeclipse客户端、SDK方式的客户端和根据WSDL自动生成的客户端。
(3)XFire与spring集成(XFire运行在spring容器中)
XFire提供了对spring的集成,可配置spring bean来提供web服务。
a、配置spring bean
在web.xml文件中增加spring的配置,同时将XFire的bean配置文件加入到spring容器中。
b、配置XFire Servlet
在spring容器中,需配置org.codehaus.xfire.spring.XFireSpringServlet类集中处理web服务的servlet请求。
c、配置web服务Bean
最后配置spring容器中的bean,此时XFire运行在spring容器中,故不再需要配置servicers.xml文件,而是在applicationContext.xml配置bean。
(4)web服务安全
作为一个服务提供商,所提供的服务若没有安全机制,则任何人都可以使用服务了。
数字签名(signature)其实是使用私钥对报文的摘要进行加密,只有报文在传输过程中不被篡改,接收端在进行数字签名验证时才可能成功。
虽然数字签名解决了完整性和不可抵赖性的安全问题,但消息体还是以明文的方式进行发送,在传输过程中,消息体的内容可能被监视。此时需要加密(encryption)。
3、CXF与Spring集成
(1)In Action
新建web工程,如cxftest。在pom.xml中添加依赖:groupId为org.apache.cxf,artifactId分别为cxf-rt-frontend-jaxws和cxf-rt-transports-http,version为2.6.2。
a、定义接口,必须加上@webservice注解,否则会报错。如:
@WebService(name="HelloService", targetNamespace="http://test.com")
public interface HelloService {
@WebMethod
@WebResult(name = "result")
public String sayHello(@WebParam(name = "s")String s);
}
b、实现类,其中@WebService注解表示是要发布的web服务,endpointInterface的值是该服务类对应的接口。如:
@WebService(name="HelloService", targetNamespace="http://test.com",endpointInterface = "com.framework.webservice.HelloService")
public class HelloServiceImpl implements HelloService{
public String sayHello(String s) {
System.out.println( "Insist on"+s);
return "Insist on";
}
}
c、spring配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="helloServiceImpl" class="com.framework.webservice.HelloServiceImpl" />
<jaxws:endpoint id="hello" implementor="#helloServiceImpl" address="/Hello" />
</beans>
implementor:指明具体的实现类;address:指明这个webservice的相对地址。
d、web.xml文件中加入,如:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml</param-value> //加载spring配置文件
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
e、部署到web服务器,webservice就发布成功了。可输入:http://localhost:8080/cxftest/Hello?wsdl,看其描述文件。
若此处为<url-pattern>/ws/*</url-pattern>,则应输入: http://localhost:8080/cxftest/ws/Hello?wsdl
f、创建客户端调用webservice测试
//创建WebService客户端代理工厂
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
//注册WebService接口
factory.setServiceClass(HelloService.class);
//设置WebService地址
factory.setAddress(http://localhost:8080/cxftest/Hello);
HelloService hello = (HelloService)factory.create();
//调用webservice接口方法
hello.sayHello("hello");//返回Insist on
3、PS
(1)在另一个web应用中调用webservice有两种方法:
一、
a、定义接口
@WebService(name="HelloService", targetNamespace="http://test.com")
public interface HelloService {
@WebMethod
@WebResult(name = "result")
public String sayHello(@WebParam(name = "s")String s);
}
b、在applicationContext.xml文件中加入:
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:client id="helloClient" serviceClass="com.framework.webservice.client.HelloService" address="http://localhost:8080/cxftest/Hello" />
c、在action中引用:
@Resource(name="helloClient")
private HelloService helloService;
之后,就可以在此action中调用此HelloService中的方法取得数据了;
二、
a、定义接口
@WebService(name="HelloService", targetNamespace="http://test.com")
public interface HelloService {
@WebMethod
@WebResult(name = "result")
public String sayHello(@WebParam(name = "s")String s);
}
b、在applicationContext.xml文件中加入:
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="helloService" class="com.framework.webservice.HelloService" factory-bean="helloClientFactory" factory-method="create"/>
<bean id="helloClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.framework.webservice.HelloService" />
<property name="address" value="http://localhost:8080/cxftest/Hello" />
</bean>
c、在action中引用:
@Resource(name="helloService")
private HelloService helloService;
之后,就可以在此action中调用此HelloService中的方法取得数据了;
(2) 客户端调用进行身份验证:
<!-- 使用拦截器配置示例-->
<jaxws:client id="client" serviceClass="com.dahua.icp.webservice.caze.CazeService" address="http://localhost:8080/tz/ws/caze" >
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="user" value="cxfClient" />
<entry key="passwordCallbackRef">
<ref bean="clientPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
(3)