手把手教你如何玩转WebService(包含项目实践)

情景引入:

时间:早晨 8 : 00 am

小白:起床起床,,,公司又来需求了,你还在睡觉,快点起来~!

我:大惊小怪,又怎么了呢?小白,别一惊一乍的,打扰我的美梦

小白:公司给了个新需求,你还记得,咱们上次做的那个项目吗?

我:记得,怎么了呢?不是都已经上线了吗?

小白:对呀,但是,与我们合作的那个公司,他们想把我们项目里面的物流查询功能,放到他们自己开发的一个系统里面去,说这样方便他们自己进行查询,要不然,老是需要额外登录我们的系统,挺麻烦的,而还要特别的给他们一个账号进行管理。所以,他们的需求就是:让物流查询的功能提供给他们。 

我:意思是他们想跨平台用我们的物流功能呢?

小白:是的,,,快,赶紧想想办法,咱们,总不能又给他们写一套一样的代码嵌入吧,这效率太低了。

我:当然不行了,这样写的话,有很多问题的,而且系统与系统进行了多重嵌入会影响整体的执行。

小白:对呀,所以,那咱们怎么办呢?

我:容我思考思考,针对这样的跨平台问题,其实也挺好解决的,那就是采取WebService的方式,我们将物流查询作为一个WebService,这样只需要他们那边进行相应的规则处理就好了。

小白:WebService??这是一个什么东西呢?有这么神奇,还可以跨平台的吗?

我:当然,这在很多地方其实都用到的,比如天气查询功能,你觉得每个公司都会去写一套这样的代码吗?当然不会。

小白:对哦,要不然这多麻烦,你看像微信公众号里面的那么多服务,都是别人写好的,我们开发都是用一定的规则去解析的。

我:对的,那下面,我来说说,到底什么是WebService和它的功能。

一:WebService简介

(1)简介----百度百科(注意标识的重点)

        Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。 [1] 
       Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。Web Service是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集XML、HTTP。Web Service减少了应用接口的花费。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。

(2)WebService三元素

UDDI:UDDI 的目的是为电子商务建立标准;UDDI是一套基于Web的、分布式的、为Web Service提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。---简单点说,就是一套规则,方便使用;

WSDL:Web Service描述语言WSDL 就是用机器能阅读的方式提供的一个正式描述文档而基于XML(标准通用标记语言下的一个子集)的语言,用于描述Web Service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的。----简单点说,就是使用规则,方便人和机器进行阅读;

SOAP协议:基于Http,基于XML,SOAP即简单对象访问协议(Simple Object Access Protocol),它是用于交换XML(标准通用标记语言下的一个子集)编码信息的轻量级协议。它有三个主要方面:XML-envelope为描述信息内容和如何处理内容定义了框架,将程序对象编码成为XML对象的规则,执行远程过程调用(RPC)的约定。SOAP可以运行在任何其他传输协议上。例如,你可以使用 SMTP,即因特网电子邮件协议来传递SOAP消息,这可是很有诱惑力的。在传输层之间的头是不同的,但XML有效负载保持相同。----简单点说,就是传输协议,方便进行传输;

(3)WebService与Socket的区别(两种通信的方式)

(1) Socket是基于TCP/IP的传输层协议。 
    Webservice是基于HTTP协议传输数据,http是基于tcp的应用层协议。 
    Webservice采用了基于http的soap协议传输数据。
(2)Socket接口通过流传输,不支持面向对象。 
    Webservice 接口支持面向对象,最终webservice将对象进行序列化后通过流传输。 
    Webservice采用soap协议进行通信,不需专门针对数据流的发送和接收进行处理,是一种跨平台的面向对象远程调用技术。
(3)Socket适用于高性能大数据的传输,传输的数据需要手动处理,socket通信的接口协议需要自定义。

二:属于自己的第一个WebService程序

1)服务端代码(Java工程项目即可,而不需要是web项目,因为webservice已经作为了java SE里面自带的内容):

package com.hnu.scw.webservice;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**  
 * <p>Title: MyFirstWebService.java</p>  
 * <p>Description: </p>  
 * <p>Company: 湖南大学</p>  
 * @author scw  
 * @date 2018年5月3日  
 */
@WebService
public class MyFirstWebService {
	/**
	 * 定义webservice服务器中的方法
	 * @param content
	 * @return
	 */
	public String testWebService(String content){
		System.out.println("我收到了你发的信息:" + content);
		return "服务器:我转发信息给你";
	}
	
	public static void main(String[] args){
		//定义自己的webservice服务器发布的地址
		String address = "http://localhost:9090/MyFirstWebService"; //这个9090端口随便定义,只要不冲突即可
		//通过该方法进行发布
		Endpoint.publish(address, new MyFirstWebService());
		//打印一句话,表示一下服务器进行了开启
		System.out.println("my webservcie starting");
	}
}

温馨提示:1:必须加@WebService注解或者@WebServiceProvider

2:至少有一个方法是public,并且不可以用static 和 final进行修饰;原因很明显,因为webservice就是提供给别人各自进行使用的,而不是保持同一个,所以不能是static ,而对于final修饰的话就是不可继承,这也是没有意义的。大家可以试试,将方法进行修改,看会不会报错。

(2)解析WebService服务器的内容

操作:在cmd命令行中执行:wsimport -s . http://localhost:9090/MyFirstWebService


结果:这样的话,就会在你执行这句话的目录下面生成对应的服务器的代码(包括.class文件和.java文件)


(3)客户端代码(Java工程项目即可):

步骤:

1:首先是把上面得到的代码中的.java文件(请注意,.class文件就不需要)拷贝到我们新建的一个客户端的java项目中

2:编写我们的测试方法

package com.hnu.scw.webservice;
import org.junit.Test;
/**  
 * <p>Title: MyTestWebService.java</p>  
 * <p>Description: 用于进行测试webservice服务器的客户端代码</p>  
 * <p>Company: 湖南大学</p>  
 * @author scw  
 * @date 2018年5月3日  
 */
public class MyTestWebService {
	@Test
	public void testWebService(){
		//获取webservice服务器对象(这里的类名,其实是从wsdl文件中的servicename标签中进行获取的)
		MyFirstWebServiceService myFirstWebServiceService = new MyFirstWebServiceService();
		//获取到我们自定义的webservice的对象
		MyFirstWebService myFirstWebServicePort = myFirstWebServiceService.getMyFirstWebServicePort();
		//调用service服务器中的方法
		String receivedInfo = myFirstWebServicePort.testWebService("您好,webservice 服务器");
		//打印从服务器的方法中得到的返回值,测试表示收到了服务器返回的内容
		System.out.println("服务器返回的内容是:" + receivedInfo);		
	}	
}

温馨提示:可以通过浏览器输入:http://localhost:端口号/发布的服务器名字?wsdl     -----------来查看定义service的wsdl文档

这时候,我们只需要首先运行服务器端的java项目,然后再运行我们客户端的@Test方法,这样就可以得到从服务器中获取到的消息内容了。

三:与WebService服务器进行交互的方式

(1)普通客户端调用

这个的话就不多说了,因为在我们上面的第一个WebService的代码中,就已经是这样的一种调用方式。

(2)ajax调用

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type="text/javascript">
		/*
			思路:
			1.创建一个XMLHTTP对象
			2.打开链接open("POST",url)
			3.设置请求头Content-Type
			4.设置回调函数,处理返回值
			5.从返回的XML中解析我们要的内容
		*/
		
		var xmlHttpReqquest = new ActiveXObject("Microsoft.XMLHTTP");
		//alert(xmlHttpReqquest);

		//发送SOAP请求
		function sendMsg(){
			//获取用户输入的内容
			var name = document.getElementById("name").value;
			var url = "http://localhost:9090/MyFirstWebService";
			//下面的这种格式主要是通过Eclipse下载了一个webservice调式工具,这样就可以看到对应的xml格式内容
			var requestBody = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://webservice.scw.hnu.com/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
							+ "<soapenv:Body><q0:testWebService><arg0>"+name+"</arg0></q0:testWebService></soapenv:Body></soapenv:Envelope>";
			xmlHttpReqquest.open("POST", url);
			xmlHttpReqquest.setRequestHeader("Content-Type","text/xml;charset=utf-8");
			xmlHttpReqquest.onreadystatechange = _back;
			xmlHttpReqquest.send(requestBody);
		}

		//接收SOAP返回,从返回XML中解析
		function _back(){
			//处理完毕,处理成功
			if(xmlHttpReqquest.readystate==4){		//处理完
				if(xmlHttpReqquest.status==200){	//成功
					var xml = xmlHttpReqquest.responseXML;
					//alert(xml);

					//获取return标签的第一个
					var ele = xml.getElementsByTagName("return")[0];
					alert(ele.text);
				}else{
					alert(0);
				}
			}
		}
	
	</script>
</head>
<body>
	<input type="text" id="name" name="name" value=""/>
	<input type="button" name="send" value="send" onclick="sendMsg();"/>
</body>
</html>

(3)URLConnection的调用方式

//创建url地址
URL url = new URL(""http://localhost:9090/MyFirstWebService");
//打开连接
URLConnection conn = url.openConnection();
//转换成HttpURL
HttpURLConnection httpConn = (HttpURLConnection) conn;
//打开输入输出的开关
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
//设置请求方式
httpConn.setRequestMethod("POST");
//设置请求的头信息
httpConn.setRequestProperty("Content-type", "text/xml;charset=UTF-8");
//拼接请求消息
String data = "<soapenv:Envelope xmlns:soapenv=" +
        "\"http://schemas.xmlsoap.org/soap/envelope/\" " +
        "xmlns:q0=\"http://server.rl.com/\" " +
        "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
        "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
        +"<soapenv:Body>"
        +"<q0:testWebService>"
        +"<arg0>my name is scw</arg0> "
      +"</q0:testWebService>"
      +"</soapenv:Body>"
      +"</soapenv:Envelope>";
//获得输出流
OutputStream out = httpConn.getOutputStream();
//发送数据
out.write(data.getBytes());
//判断请求成功
if(httpConn.getResponseCode() == 200){
    //获得输入流
    InputStream in = httpConn.getInputStream();
    //使用输入流的缓冲区
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuffer sb = new StringBuffer();
    String line = null;
    //读取输入流
    while((line = reader.readLine()) != null){
        sb.append(line);
    }
    //创建sax的读取器
    SAXReader saxReader = new SAXReader();
    //创建文档对象
    Document doc = saxReader.read(new StringReader(sb.toString()));
    //获得请求响应return元素
    List<Element> eles = doc.selectNodes("//return");
    for(Element ele : eles){
        System.out.println(ele.getText());
    }
}

(4)QName调用------------推荐这种方式

package com.hnu.scw.test;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import org.junit.Test;
import com.hnu.scw.webservice.MyFirstWebService;
/**  
 * <p>Title: MyTestQNameWebService.java</p>  
 * <p>Description: 通过QName的一种调用方式</p>  
 * <p>Company: 湖南大学</p>  
 * @author scw  
 * @date 2018年5月4日  
 */
public class MyTestQNameWebService {
	@Test
	public void test() throws MalformedURLException{
		//创建一个连接(地址对应的就是webservice服务器中的地址)
		URL wsdlDocumentLocation = new URL("http://localhost:9090/MyFirstWebService?wsdl");
		//这个参数,主要是根据我们设定的webService的接口来进行的
		QName serviceName = new QName("http://webservice.scw.hnu.com/","MyFirstWebServiceService");
		Service ws = Service.create(wsdlDocumentLocation , serviceName );
		//获取到调用的对象内容
		MyFirstWebService port = ws.getPort(MyFirstWebService.class);
		//方法的调用
		String result = port.testWebService("my name is scw");
		System.out.println(result);
	}
}

温馨提示:(1)这个方式大体和我们之间进行的客户端调用类型,但是注意一点,在我们的客户端的方式的时候,我们是把所解析得到的.java所有文件都拷贝到客户端程序,而如果用QName的形式,我们只需要保留我们对应WebService类的接口那个即可。比如,如下:

客户端的情况:


QName的情况:


(2)当我们只保留上面的java文件的时候,会出现错误,只需要根据下面进行修改即可;


(3)QName对象的参数是如何知道的?那么久看我们保留的那个接口类中;


(4)通过QName的方式可以很明显的感觉比第一种客户端要好,因为,可以对于端口和链接都有灵活性,而且拷贝的代码也相对较少;

四:关于WebService的部分注解


五:初识CXF框架

     官网:http://cxf.apache.org/

    Apache CXF = Celtix + XFire,开始叫 Apache CeltiXfire,后来更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。Apache CXF已经是一个正式的Apache顶级项目。

      Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。

六:利用CXF框架来搭建我们的WebService

步骤:

(1)首先去官网下载一个版本http://cxf.apache.org/,现在的话,都是3.2.X版本了,这个根据需要即可;

(2)下载之后,里面就有一个lib的目录,就是关于CXF架构的一些依赖包;

可以去官网下载(或者去博文最后的百度云中下载):http://cxf.apache.org/

(3)创建一个web项目(注意:这时候用了web项目,而之前的开发都是用的Java项目),并且把依赖包都复制到项目中的lib目录中(就和正常的开发web项目一样,在拷贝所有的之后,要把里面的WHICH_JARS这个文件删除,否则会报错

服务端代码:

package com.hnu.scw;
import org.apache.cxf.frontend.ServerFactoryBean;
/**
 * 基于CXF框架的服务端代码
 * @author Administrator
 *
 */
public class FirstCXFService {
	/**
	 * web服务的方法
	 * @param name
	 * @return
	 */
	public String printReciveInfo(String name){
		System.out.println("客户端发送过来信息:" + name);
		return "服务器转发给你了"+ name;
	}	
	public static void main(String[] args){
		ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
		//设置访问地址
		serverFactoryBean.setAddress("http://localhost:9090/firstService");
		//设置实现类
		serverFactoryBean.setServiceClass(FirstCXFService.class);
		//启动服务
		serverFactoryBean.create();
	}
}

温馨提示:不要运行配置的服务器,而是直接运行main函数即可。。。。。这样就开启可服务器

客户端代码:(同样的还是通过cmd中的命令:wsimport -s .  XXXXXXXXXX (SOAP1.1版本)或者wsdl2java –d . XXXXXXXXXX(SOAP1.2版本) 来生成代码),然后再创建一个工程项目,并把生成的.java文件拷贝进去。

package com.hnu.scw.test;
import org.junit.Test;
import com.hnu.scw.FirstCXFService;
import com.hnu.scw.FirstCXFServicePortType;
/**
 * 测试CXF框架的客户端
 * @author Administrator
 *
 */
public class CXFClientTest {
	@Test
	public void printTest(){
		FirstCXFService firstCXFService = new FirstCXFService();
		FirstCXFServicePortType firstCXFServicePort = firstCXFService.getFirstCXFServicePort();
		String result = firstCXFServicePort.printReciveInfo("my name is scw");
		System.out.println(result);
	}
}


七:面向接口的编写WebService服务

接口:

package com.hnu.scw;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;
@WebService(serviceName="HelloServer")
@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)			
public interface FirstServer {
	@WebMethod(operationName="sayHello")
	@WebResult(name="returnMsg")
	public String printReciveInfo(@WebParam(name="name")String name);
}

服务器端实现类:

package com.hnu.scw;
import org.apache.cxf.frontend.ServerFactoryBean;
/**
 * 基于CXF框架的服务端代码
 * @author Administrator
 *
 */
public class FirstCXFService implements FirstServer{
	/**
	 * web服务的方法
	 * @param name
	 * @return
	 */
	public String printReciveInfo(String name){
		System.out.println("客户端发送过来信息:" + name);
		return "服务器转发给你了"+ name;
	}
	
	public static void main(String[] args){
		ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
		//设置访问地址
		serverFactoryBean.setAddress("http://localhost:9090/firstService");
		//设置接口
		serverFactoryBean.setServiceClass(FirstServer.class);
		//设置实现类
		serverFactoryBean.setServiceBean(new FirstCXFService());
		//启动服务
		serverFactoryBean.create();
	}
}

客户端类型的方法就不多说了,只是需要重新编译下载服务端的代码即可。

八:在WebService服务端添加输入输出监控日志

 方法:其实很简单,就是添加一些默认的拦截器就可以了

服务端代码:

package com.hnu.scw;
import org.apache.cxf.frontend.ServerFactoryBean;
/**
 * 基于CXF框架的服务端代码
 * @author Administrator
 *
 */
public class FirstCXFService {
	/**
	 * web服务的方法
	 * @param name
	 * @return
	 */
	public String printReciveInfo(String name){
		System.out.println("客户端发送过来信息:" + name);
		return "服务器转发给你了"+ name;
	}	
	public static void main(String[] args){
		ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
		//设置访问地址
		serverFactoryBean.setAddress("http://localhost:9090/firstService");
		//设置实现类
		serverFactoryBean.setServiceClass(FirstCXFService.class);
		//拦截器
		serverFactoryBean.getInInterceptors().add(new LoggingInInterceptor());		//拦截请求的链接,打印相关信息(谁调用)
		serverFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());		//拦截响应的链接,打印相关信息(返回)
		//启动服务
		serverFactoryBean.create();
	}
}

九:设置WebService的版本是采取SOAP1.2版本

   在前面有说过,JDK是默认支持SOAP1.1版本的,而现在也有1.2版本,那如何将我们的WebService转变成1.2版本的呢?其实很简单,只需要添加一个注解即可:(如果采取的是接口编程,那么就放在接口名上即可)

@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)

小知识:SOAP1.1和SOAP1.2的区别:

1)命名空间

2)标签变化

温馨提示:在开发中如果使用SOAP1.2实现WebService,在生成本地调用代码时,应该使用CXF提供wsdl2java命令。如果使用SOAP1.1实现WebService,在生成本地调用代码时,应该使用jdk提供wsimport命令。在实际项目中目前尽量使用SOAP1.1版本;

十:CXF和Spring框架的整合(重点知识)

步骤:

(1)导包:将下载下来的CXF中的lib目录中jar导入到web项目中的WEB-INF目录下的lib中(同样,还是需要将其中的WHICH_JARS这个文件删除,否则会报错),不需要额外导入Spring的包,因为在CXF的lib中已经包含有Spring的jar包,这个自己可以进行查看;

(2)创建WebService的类;

比如:

package com.hnu.scw.webservice;
import javax.jws.WebService;
/**
 * 创建一个webservice服务类
 * @author scw
 *
 */
@WebService
public class MyWebService {
	/**
	 * 创建WebService的调用方法
	 * @param content
	 * @return
	 */
	public String hiMyService(String content){
		System.out.println("客户端发送过来了:" + content);
		return "服务器返回:"+ content ;
	}
}

(3)在WEB-INF目录下面创建一个cxf-servlet.xml-------------------这个就是对于webservice的管理

<?xml version="1.0" encoding="UTF-8"?>
<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/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
    
    <!-- 加载提供的服务 -->
    <jaxws:endpoint id="helloService" address="/mywebservice" implementor="com.hnu.scw.webservice.MyWebService"></jaxws:endpoint>
</beans>

(4)修改web.xml文件内容,将WebService的cxf-servlet.xml进行管理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee           http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>cxf</display-name> 
    <!-- 配置cxf框架 cxf-servlet.xml -->
    <servlet>
    	<servlet-name>cxf</servlet-name>
    	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>cxf</servlet-name>
    	<!-- 这里配置只针对/cxf/的这样链接进行管理,因为如果也配置成/*这样的话,也是可以,这只是更加便于管理而已 -->
    	<url-pattern>/cxf/*</url-pattern>
    </servlet-mapping>
</web-app>

(5)启动tomcat项目,测试CXF的配置是否成功


(6)配置Spring的配置文件中的beans.xml,专门进行bean的内容的管理(在项目的src下即可,这和Spring开发没什么不同)

主要是为了将WebService的类放入到Spring中进行管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
			http://www.springframework.org/schema/mvc 
			http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
			http://www.springframework.org/schema/context 
			http://www.springframework.org/schema/context/spring-context-3.0.xsd 
			http://www.springframework.org/schema/aop 
			http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
	<bean id="myWebService" class="com.hnu.scw.webservice.MyWebService"></bean>	 <!--这就是我的webservice类的路径-->	
</beans>			

(7)修改之前的cxf-servlet.xml中的内容

原因:因为现在我们的bean放入到了Spring中进行管理,所以,我们直接引用Spring中的bean即可

<?xml version="1.0" encoding="UTF-8"?>
<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/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
    
    <!-- 加载提供的服务 ,注意看此时的implementor标签的写法,#表示的是引用Spring中的bean内容-->
    <jaxws:endpoint id="helloService" address="/mywebservice" implementor="#myWebService"></jaxws:endpoint>
</beans>

(8)修改web.xml内容,将Spring放入到容器进行管理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee           http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>cxf</display-name>
    
    <!-- 配置spring框架 beans.xml -->
    <context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>classpath:beans.xml</param-value>
    </context-param>
    <listener>
    	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- 配置cxf框架 cxf-servlet.xml -->
    <servlet>
    	<servlet-name>cxf</servlet-name>
    	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>cxf</servlet-name>
    	<!-- 这里配置只针对/cxf/的这样链接进行管理,因为如果也配置成/*这样的话,也是可以,这只是更加便于管理而已 -->
    	<url-pattern>/cxf/*</url-pattern>
    </servlet-mapping>
</web-app>

(9)启动tomcat,进行测试是否整合成功


总结:通过上面的步骤,我们的整合已经成功了,但是大家可能发现有很多地方不是很好,比如我们的cxf-servlet.xml是放在WEB-INF目录下,那么我们应该也像配置Spring的配置文件一样,放在src下这样的话将会更加好,所以,我们进行下面的修改

 (10)修改cxf-servlet.xml的加载路径----------这样我们就可以把这个xml放到src目录下了

 <!-- 配置cxf框架 cxf-servlet.xml -->
    <servlet>
    	<servlet-name>cxf</servlet-name>
    	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    	<!-- 配置cxf-servlet.xml的寻找的位置 -->
    	<init-param>
    		<param-name>config-location</param-name>
    		<param-value>classpath:cxf-servlet.xml</param-value>
    	</init-param>
    </servlet>
    <servlet-mapping>
    	<servlet-name>cxf</servlet-name>
    	<!-- 这里配置只针对/cxf/的这样链接进行管理,因为如果也配置成/*这样的话,也是可以,这只是更加便于管理而已 -->
    	<url-pattern>/cxf/*</url-pattern>
    </servlet-mapping>

--------------------------------------------------------------------------------------------

项目整体结构如下:


------------------------------------------------------------------------------------------------

十一:项目实践

前提内容:这是一个比较经典的物流供应项目,网上可以找到源码的。只不过,既然我们学得是WebService,那么肯定就要进行相应的改造的,所以,针对里面的一个物流查询模块,来设计成为一个能够让其他系统都能调用的功能(这样,情景引入的问题是不是就解决了)。

描述:针对项目中的,物流查询模块改造成一个WebService服务,方便其他的模块或者系统进行相应的使用,实现一种跨平台的功能。

步骤:

环境:eclipse + maven + mysql (其他的编辑器什么的都行,这个完全根据自身习惯即可,没有要求)

(1)导入项目内容--------这个不多说,就是导入maven项目,然后把相应的数据库内容在本地生成即可(都在我的百度云里面了)

(2)查看原始内容(重点关注我标识的部分,也就是我们要进行改造的类)



我们就改造下面这个方法:这个方法的功能就是,通过物流的ID,来查询到它的物流信息


提示:大家稍微看一下这个类,基本了解是干嘛的就可以了哈~~

改造其类为WebService类步骤(重点来了):

(1)将需要修改为WebService的类,添加注解 @WebService进行标识


(2)添加操作对应的DAO类的额外bean依赖

//给WebService使用
	@WebMethod(exclude=true)
	public void setExportDao(ExportDao exportDao) {
		this.exportDao = exportDao;
	}

分析:

1:添加@WebMethod(exclude=true)的作用:防止给调用者看到这个方法,因为这个方法只是给spring来进行注入bean依赖的;

2:大家可能注意到一个问题了,在spring开发中,

我们一般是这样。

但是,千万注意一下,这个也是要的,而为什么又多了一个set注入,是因为,这是专门用户webservice注入的,所以,一定要区分开原因,所以这两者都是需要存在的。也就是下面的这样的代码:

//给spring service使用dao
	@Resource
	ExportDao exportDao;
	
	//给WebService使用
	@WebMethod(exclude=true)
	public void setExportDao(ExportDao exportDao) {
		this.exportDao = exportDao;
	}

(3)将其他不进行提供webservice调用的方法进行注解屏蔽,而只保留webservice能够调用的方法。如下所示:

@WebMethod(exclude=true)
	public List<Export> find(Map paraMap) {
		return exportDao.find(paraMap);
	}

	//WebService调用
	public Export get(String id) {
		return exportDao.get(id);
	}

(4)添加cxf-servlet.xml文件

目录:

cxf-servlet.xml添加的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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/schemas/jaxws.xsd">
					
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
   
	<!-- 发布WebService 参数:访问地址address,实现类 implementor -->
	<bean id="exportService" class="cn.itcast.jk.service.impl.ExportServiceImpl">
		<property name="exportDao" ref="exportDaoImpl"/>
	</bean>
	
	<jaxws:endpoint address="/ExportServiceImpl" implementor="#exportService"/>
</beans>

分析:现在再回头看一下第(2)步中,额外添加的set注入,是不是就明白原因了呢?这上面的知识都是我上面讲过的,所以,不懂的就回头再去看看吧。

(5)修改web.xml,添加对cxf-servlet.xml的加载

<!-- 3.webService CXF -->
  <servlet>
  	<servlet-name>cxf</servlet-name>
  	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  	<init-param>
  		<param-name>config-location</param-name>
  		<param-value>classpath:cxf-servlet.xml</param-value>
  	</init-param>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>cxf</servlet-name>
  	<url-pattern>/cxf/*</url-pattern>
  </servlet-mapping>

(6)在pom.xml中添加对CXF框架的依赖

<!-- 整合CXF WebService框架 -->
		<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.2</version>
        </dependency>

分析:通过上面的步骤,基本上就改造完成了,那么下面就来进行实际的使用:(这里通过ajax的形式来进行,也是我们开发中用的相对较多的方式)

(7)ajax来调用webservice类的形式

具体的内容:大家就看代码中:src\main\webapp\WEB-INF\pages\cargo\export目录下的ajaxExport.jsp页面内容吧

(8)进行测试。(当然,这个最好是在整合完成CXF和Spring,即改造完webservice类的时候就测试一下比较好)

针对这个项目的话,我把最初的项目源码和改造后的代码以及数据库内容,两个版本的都放入了百度云,而且把该博文中相关的代码都放入了这里面,供大家进行下载。

链接:https://pan.baidu.com/s/1_exUqQeg3h2OwGFhDa2dmg          密码:60fq

总结:我想没有比这篇博文更加详细的介绍了的吧。^_^~!WebService其实开发起来并不难,而且功能还是非常强大,对于如果存在着异构系统之间的调用的话,还是挺实用的。所以,对于这部分的内容,就介绍到这里了,欢迎大家的关注哦~

猜你喜欢

转载自blog.csdn.net/cs_hnu_scw/article/details/80181762