WebService与CXF

    xiaoxiao2022-07-02  143

    WebService简介

    Webservice也叫XML Web Service,Web服务。可使用开放的xml标准来描述、发布、发现、协调和配置这些应用程序。用于开发分布式的互操作的应用程序。是一种跨编程语言、跨操作系统、跨网络的远程服务器调用技术。 WebService,顾名思义就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用. 我们可以调用互联网上查询天气信息Web服务,然后将它嵌入到我们的程序(C/S或B/S 程序)当中来,当用户从我们的网点看到天气信息时,他会认为我们为他提供了很多的信息服务,但其实我们什么也没有做,只是简单了调用了一下别人服务器上的一段代码而已。 学习WebSerice可以将你的服务(一段代码)发布到互联网上让别人去调用,也可以调用别 人机器上发布的WebService,就像使用自己的代码一样.。 webservice可以实现跨平台远程调用,从而实现异构程序之间的通信,特定需求下可以实现远程数据共享、软件重用、分布式程序集成。 webservice 即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术即跨平台远程调用技术。 它采用标准SOAP协议(Simple Object Access Protocol) ,协议传输webservice数据,是w3c标准。 xml和XSD(XML Schema Datatypes)是webservice的基础,是w3c标准,采用wsdl作为描述语言即webservice使用说明书。

    (webservice的生活中的例子:http://www.51240.com/(便民查询网站))

    以各个网站显示天气预报功能为例: 气象中心的管理系统将收集的天气信息并将数据暴露出来(通过WebService Server), 而各大站点的应用就去调用它们得到天气信息并以不同的样式去展示(WebService Client). 网站提供了天气预报的服务,但其实它们什么也没有做,只是简单了调用了一下气象中心服务器上的一段代码而已。

    web Service原理

     Webservice是使用Http发送SOAP协议的数据的一种远程调用技术  Webservice要开发服务端  Webservice要开发客户端  Webservice客户端开发需要阅读服务端的使用说明书(WSDL) 服务端

    public class WeatherServer { public static void main(String[] args) throws Exception { Map<String, String> map=new HashMap<String, String>(); map.put("北京", "天气晴"); map.put("成都", "小雨"); map.put("深圳", "阴天"); //创建Socket ServerSocket serverSocket=new ServerSocket(8888); System.out.println("服务器端开始启动...监听端口:8888"); while(true){ //接收客户端的请求,accept为阻塞方法 Socket socket=serverSocket.accept(); //接收客户端数据 DataInputStream inputStream=new DataInputStream(socket.getInputStream()); //响应客户端数据 DataOutputStream outputStream=new DataOutputStream(socket.getOutputStream()); String city = inputStream.readUTF(); System.out.println("正在查询城市数据:"+city); String result=map.get(city); outputStream.writeUTF(result); } } }

    客户端 public class WeatherClient {

    public static void main(String[] args) throws Exception { Scanner input=new Scanner(System.in); System.out.print("请输入要查询的城市:"); String city = input.next(); Socket socket=new Socket("127.0.0.1",8888); //发送数据到服务器 DataOutputStream outputStream=new DataOutputStream(socket.getOutputStream()); //接收服务器发送的数据 DataInputStream inputStream=new DataInputStream(socket.getInputStream()); outputStream.writeUTF(city); //readUTF也是一个阻塞的方法,输出查询结果 String result = inputStream.readUTF(); System.out.println("查询结果:"+result); }

    }

    总结:webservice的底层原理,就是socket

    1. Web Service中的几个重要术语

    1.1. WSDL:web service definition language 直译 : WebService定义语言

    对应一种类型的文件.wsdl (告诉客户端如何调用接口)定义了web service的服务器端与客户端应用交互传递请求和响应数据的格式和方式一个web service对应一个唯一的wsdl文档

    1.2. SOAP:simple object access protocal 直译: 简单对象访问协议

    是一种简单的、基于HTTP和XML的协议, 用于在WEB上交换结构化的数据soap消息:请求消息和响应消息http协议+xml片断=SOAP协议

    SOAP协议 = HTTP协议 + XML数据格式

    SOAP1.1和SOAP1.2区别

    相同点: 请求发送方式相同:都是使用POST 协议内容相同:都有Envelope和Body标签 不同点: 数据格式不同:content-type不同 SOAP1.1:text/xml;charset=utf-8 SOAP1.2:application/soap+xml;charset=utf-8 命名空间不同: SOAP1.1:http://schemas.xmlsoap.org/soap/envelope/ SOAP1.2:http://www.w3.org/2003/05/soap-envelope 1.3. UDDI UUDI:目录服务 (租客 和 房东 之间的 中介!)

    UDDI:Universal Description, Discovery and Integration.可译为"通用描述,发现与集成服务"。 服务目录检索 企业可以使用它对 Web services 进行注册和搜索. 企业将自己提供的Web Service注册在UDDI,也可以使用别的企业在UDDI注册的web service服务,从而达到资源共享。UDDI旨在将全球的webservcie资源进行共享,促进全球经济合作。 UDDI现状: 目前大部分企业使用webservice并不是必须使用UDDI,因为用户通过WSDL知道了web service的地址,可以直接通过WSDL调用webservice。

    jdk发布webservice服务 使用JAX-WS开发webservice JAX-WS 的全称为 Java API for XML-Based Webservices ,从java5开始支持JAX-WS2.0版本,Jdk1.6.0_13以后的版本支持2.1版本,jdk1.7支持2.2版本 那么如何才可以发布一个WebService呢? 1:用Jdk1.6.0_13以后的版本发布一个WebService服务,并通过地址栏查看它的wsdl文档. 2:通过wsimport生成客户端代码,调用并查看运行的结果.(学会如何调用是我们的重点). 3:从互联网上获取一个WebService网络公开的服务,并使用工具生成客户端,调用并查看结果。

    测试代码包括服务端和客户端的开发

    3.1 服务端开发

    @WebService public class JdkWeatherbServer { public String queryWeather(String cityName){ System.out.println("客户端查询参数:"+cityName); String result="晴转多云"; return result; } public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:8888/weather", new JdkWeatherbServer()); System.out.println("服务器端启动...."); } }

    其中: 1、编写SEI(Service Endpoint Interface),为了开发方便我们用java类代替接口加实现类的方式。 2、java类中至少要有一个非静态的公开方法需要作为webservice服务方法。 3、public class WeatherServer上边要加上@WebService,表示webservice的发布类。 4、使用Endpoint.publish()方法发布服务。 3.2 查看使用说明书(wsdl) 1、在地址栏输入(注意后面的参数?wsdl) http://127.0.0.1:8888/weather?wsdl 发布完WebService就会得到Wsdl说明书! 2、 这里注意目前不是访问webService,只是获取一个用于描述WebService的说明文件,即:wsdl文件,我们需要看懂wsdl的文件,这样就知道服务端究竟发布什么样的服务,提供什么样的方法,需要传递什么类型的参数,方法的返回值类型是什么等。. 3、 wsdl- 即WebServiceDescriptionLanguage,是以XML文件形式来描述WebService的”说明书”,有了说明书,我们才可以知道如何使用或是调用这个服务。 这里从下向上看: 其中: 1:JdkWeatherServerService为视图服务 2:WeatherServerPort为调用的端口,即getJdkWeatherServerPort()方法 3:JdkWeatherServer为接口,接口中提供一个queryWeather()的方法

    3.3 客户端开发 wsimport是jdk自带的,可以根据wsdl文档生成客户端调用代码的工具.当然,无论服务器端的WebService是用什么语言写的,都将在客户端生成Java代码.服务器端用什么语言编写的并不重要. wsimport.exe位于JAVA_HOME\bin目录下. 例如:在cmd的窗口下执行wsimport可以看到

    Wsimport 程序可以根据wsdl webservice说明书 生成客户端调用代码! 常用参数为: • -d<目录> - 将生成.class文件。默认参数。 • -s<目录> - 将生成.java文件。 • -p<生成的新包名> -将生成的类,放于指定的包下。 • (wsdlurl) - http://server:port/service?wsdl,必须的参数。

    wsimport其他参数说明,我们经常使用的参数为-d,-s,-p -d<目录>将会生成.class文件. 示例:wsimport –d . http://127.0.0.1:8888/weather?wsdl -s<目录>将会生成.java文件. 示例:wsimport –s . http://127.0.0.1:8888/weather?wsdl -p<包名>将生成的文件(.java或是.class修改成指定的包名) 示例:wsimport -s . -p com.bruceliu.client1 http://127.0.0.1:8888/weather?wsdl

    示例: C:/> wsimport -s . -p com.bruceliu.client1 http://127.0.0.1:8888/weather?wsdl 注意:-s不能分开,-s后面有个小点

    在cmd的窗口执行: 在C盘看到客户端生成的java文件: 将.java的文件整个包拷贝到客户端的工程下,然后使用WeatherClient的客户端测试,测试代码如下

    public class JdkWeaterClient { public static void main(String[] args) { //定义服务视图 JdkWeatherbServerService jdkWeatherbServerService=new JdkWeatherbServerService(); //通过服务视图找到对应的端口类型,即(portType) JdkWeatherbServer jdkWeatherbServer=jdkWeatherbServerService.getJdkWeatherbServerPort(); //通过端口类型调用webService方法 String result = jdkWeatherbServer.queryWeather("北京"); System.out.println("天气:"+result); } }

    其中JdkWeatherServiceService为服务器类 其中JdkWeatherServer为接口类 其中getWeatherServerPort为端口类型 其中queryWeather为调用的方法 这四个参数在wsdl的使用说明书中都会看到。 通常用于描述服务的名称,即new WeatherServerService ();-通常称为服务名。 在元素内的即new JkdWeatherServerService ().getJdkWeatherServerPort (); - 通常称为服务端口。 是服务接口名。即: JdkWeatherServer weatherServer = new JdkWeatherServerService ().getJdkWeatherServerPort ();

    调用第三方提供的webService服务 互联网上面有很多的免费webService服务,我们可以调用这些免费的WebService服务,将一些其他网站的内容信息集成到我们的Web应用中显示,下面就以获取天气预报数据和查询国内手机号码归属地为例进行说明。 气象中心的管理系统将收集的天气信息并将数据暴露出来(通过WebService Server), 而各大站点的应用就去调用它们得到天气信息并以不同的样式去展示(WebService Client). Webservice的网络网址:www.webxml.com.cn

    4.1 调用免费的web service获取天气预报信息  找到提供天气预报信息的Webservice的网络地址 http://ws.webxml.com.cn/WebServices/WeatherWS.asmx 访问结果如下图所示: 找到WebService的wsdl描述,通过URL地址http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl:如下: 客户端编码方式访问第三方提供的webService服务   1、借助wsimport命令工具自动生成客户端代码 创建一个测试项目,如下:

    打开命令行窗口,切换到项目的src目录,执行”wsimport -s . http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl” 执行客户端代码 2、如下图所示: 运行结果显示,使用wsimport工具直接生成客户端代码会抛异常, 无法生成客户端代码, 只是因为我们要调用的WebService是用.net写的,这个是Java调用net的webservice都有的问题,这个问题的解决办法如下:

    将对应的wsdl文档保存到本地

    2、修改wsdl文档的部分内容:将 <s:element ref=“s:schema” /><s:any /> 替换成 <s:any minOccurs=“2” maxOccurs=“2”/>

    再次执行wsimport生成代码,这次使用保存在本地的WeatherWS.wsdl文件来进行生成,如下图所示: wsimport -s . C:\WeatherWS.wsdl 从执行结果显示,这一次可以正常生成代码了,就可以看到生成的代码了,如下图所示: 把生成的Java代码拷贝到工程中:

    测试客户端代码:

    public class WeatherWSClient { public static void main(String[] args) { // 创建一个WeatherWS工厂 WeatherWS factory = new WeatherWS(); // 根据工厂创建一个WeatherWSSoap对象 WeatherWSSoap weatherWSSoap = factory.getWeatherWSSoap(); // 调用WebService提供的getWeather方法获取南宁市的天气预报情况 ArrayOfString weatherInfo = weatherWSSoap.getWeather("成都", null); List<String> lstWeatherInfo = weatherInfo.getString(); // 遍历天气预报信息 for (String string : lstWeatherInfo) { System.out.println(string); System.out.println("------------------------"); } } }

    4.2 调用免费的web service查询国内手机号码归属地  找到提供服务的Webservice的网络地址   http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx 如下所示: 找到WebService的wsdl描述信息,通过URL地址http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl:如下: 根据WebService的wsdl描述生成客户端代码 打开命令行窗口,切换到Phone_Client的src目录,执行 wsimport -s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl 如下图所示: 测试代码:

    public class PhoneWsClient { public static void main(String[] args) { // 创建一个MobileCodeWS工厂 MobileCodeWS factory = new MobileCodeWS(); // 根据工厂创建一个MobileCodeWSSoap对象 MobileCodeWSSoap mobileCodeWSSoap = factory.getMobileCodeWSSoap(); // //调用WebService提供的getMobileCodeInfo方法查询手机号码的归属地 String searchResult = mobileCodeWSSoap.getMobileCodeInfo("13366741011",null); System.out.println(searchResult); } }

    该种方式使用简单,但一些关键的元素在代码生成时写死到生成代码中,不方便维护,所以仅用于测试。

    客户端编程调用 推荐

    public static void main(String[] args) throws Exception { /** * 参数1:wsdl地址 参数2:服务名称 */ URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl"); /** * 参数1:命名空间地址 targetNamespace="http://WebXml.com.cn/" 参数2:服务视图名称 * ,service的name值 */ QName qName = new QName("http://WebXml.com.cn/", "MobileCodeWS"); Service service = Service.create(url, qName); // 2.获取服务实现类 MobileCodeWSSoap mobileCodeWSSoap = service.getPort(MobileCodeWSSoap.class); // 3.调用查询方法 String result = mobileCodeWSSoap.getMobileCodeInfo("电话号码", ""); System.out.println(result); }

    该种方式可以自定义关键元素,方便以后维护,是一种标准的开发方式

    4. JAX-WS注解 webservice的注解开发 (了解)

    如何才可以修改wsdl文件的内容? 使用WebService的注解。WebService的注解都位于javax.jws包下: • @WebService-定义服务,在public class上边 name属性:接口名称 portName属性:端口名称 serviceName属性:定义服务器端的类 targetNamespace属性:目标包文件

    • @WebMethod-定义方法,在公开方法上边 哪一个方法要作为服务发布 @WebMethod对所有非静态的公共方法对外暴露为服务. 对于静态方法或非public方法是不可以使用@WebMethod注解的. 对public方法可以使用@WebMethod(exclude=true)定义为非对外暴露的服务。 • @WebResult-定义返回值,在方法返回值前边 对方法的返回值进行配置 • @WebParam-定义参数,在方法参数前边 对方法的参数进行配置

    1:通过WebService的注解,可以更加形像的描述Web服务。从而生成WSDL文档。 2:当修改了WebService注解之后,同时会影响客户端生成的代码。 3:调用的方法名和参数名也发生了变化。 4:服务类加上注解以后再次通过wsimport生成源代码然后调用。

    服务端代码 @WebService(name="myName",portName="myPortName",serviceName="myServiceName",targetNamespace="com.webservice") public class WeatherServer01 { @WebMethod(operationName="myMethod") public @WebResult(name="myResult") String queryWeather(@WebParam(name="myParam") String cityName){ if("北京".equals(cityName)){ return "晴天白云"; }else if("成都".equals(cityName)){ return "阴雨绵绵"; }else{ return "风平浪静"; } } public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:8888/weather", new WeatherServer01()); System.out.println("天气服务已经发布....."); } }

     生成的WSDL 客户端

    public class MyClient { public static void main(String[] args) { MyName myName = new MyServiceName().getMyPortName(); String result = myName.myMethod("成都"); System.out.println("当前天气:"+result); } }

    5. CXF安装和配置

    CXF简介

    Apache CXF = Celtix + XFire

    1)CXF是一个开源的webservice框架,提供很多完善功能,可以实现快速开发 2)CXF支持的协议:SOAP1.1/1.2,REST。 3)CXF支持数据格式:XML,JSON(仅在REST方式下支持) 4)并可以与Spring进行快速无缝的整合 5)灵活的部署:可以运行有Tomcat,Jboss,Jetty(内置),IBMWS,BeaWS上面。 CXF的安装和配置 下载:http://cxf.apache.org/download.html 直接解压到某个盘下就可以使用: CXF的环境变量的配置 环境变量: • JAVA_HOME, • CXF_HOME • Path = %JAVA_HOME%\bin;%CXF_HOME%\bin; • CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar cxf发布WebService 服务端程序 (1)创建一个java工程,添加所需要依赖的Jar包(目录下全部的jar包) (2)创建SEI接口,要加入@WebService接口 备注:@BindingType(SOAPBinding.SOAP12HTTP_BINDING)表示发布SOAP1.2的服务端

    @WebService @BindingType(SOAPBinding.SOAP12HTTP_BINDING) public interface WeatherInterface { public String queryWeather(String cityName); }

    (3)创建SEI接口实现类

    public class WeatherInterfaceImpl implements WeatherInterface { @Override public String queryWeather(String cityName) { if ("成都".equals(cityName)) { return "冷且霾"; } else { return "暖且晴"; } } }

    (4)发布服务(使用JaxWsServerFactoryBean发布)

    public class WeatherServer { // 用JaxWsServerFactoryBean发布服务,设置3个参数,1.服务接口;2.服务实现类;3.服务地址; public static void main(String[] args) { JaxWsServerFactoryBean factoryBean = new JaxWsServerFactoryBean(); // 设置服务接口 factoryBean.setServiceClass(WeatherInterface.class); // 设置服务实现类 factoryBean.setServiceBean(new WeatherInterfaceImpl()); // 设置服务地址 factoryBean.setAddress("http://127.0.0.1:8888/weather"); // 发布 factoryBean.create(); System.out.println("服务发布成功..."); } }

    附录: 服务器端发布的类  ServerFactoryBean  JaxWsServerFactoryBean(建议使用) 2个对象,都可以发布服务端,但是我们建议使用JaxWsServerFactoryBean,因为它生成的wsdl文件更加规范。 服务器端的拦截器: // 输入拦截器 jaxWsServerFactoryBean.getInInterceptors().add(new LoggingInInterceptor()); // 输出拦截器 jaxWsServerFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor()); 目的是用来输出响应的头部信息,可以看到soap协议的格式(http请求+Xml数据): 例如: Soap1.2:

    ---------------------------- ID: 1 Address: http://127.0.0.1:8888/weather Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[*/*], Cache-Control=[no-cache], connection=[keep-alive], Content-Length=[202], content-type=[text/xml; charset=UTF-8], Host=[127.0.0.1:8888], Pragma=[no-cache], SOAPAction=[""], User-Agent=[Apache-CXF/3.2.6]} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:queryWeather xmlns:ns2="http://demo.weather.com/"><arg0>成都</arg0></ns2:queryWeather></soap:Body></soap:Envelope> -------------------------------------- 十月 06, 2018 11:07:22 上午 org.apache.cxf.services.WeatherInterfaceService.WeatherInterfacePort.WeatherInterface 信息: Outbound Message --------------------------- ID: 1 Response-Code: 200 Encoding: UTF-8 Content-Type: text/xml Headers: {} Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:queryWeatherResponse xmlns:ns2="http://demo.weather.com/"><return>冷且霾</return></ns2:queryWeatherResponse></soap:Body></soap:Envelope> --------------------------------------

    (5)测试服务是否发布成功,阅读使用说明书.直接访问即可 客户端程序 (1)生成客户端代码 1.1 wsdl2java命令是CXF提供的生成客户端的工具,他和wsimport类似,可以根据WSDL生成客户端代码 1.2 wsdl2java常用参数: -d,指定输出目录 -p,指定包名,如果不指定该参数,默认包名是WSDL的命名空间的倒序 1.3 wsdl2java支持SOAP1.1和SOAP1.2

    完整示例: wsdl2java -p com.weather.client -d . http://127.0.0.1:8888/weather?wsdl //根据指定说明书地址生成客户端代码 -p指定生成的包名 -d .表示输出到当前目录

    (2)使用说明书,使用生成代码调用服务端 //使用JaxWsProxyFactoryBean调用服务端,设置2个参数,1.设置服务接口;

    public class WeatherClient { public static void main(String[] args) { JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean(); // 设置服务接口 factoryBean.setServiceClass(WeatherInterface.class); // 设置服务地址 factoryBean.setAddress("http://127.0.0.1:8888/weather"); // 获取服务接口实例 WeatherInterface weatherInterface = factoryBean .create(WeatherInterface.class); // 调用查询方法 String string = weatherInterface.queryWeather("成都"); System.out.println(string); } }

    CXF+Spring整合

    服务器程序 (1)创建一个web工程 (2)导入jar包

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.webservice.demo</groupId> <artifactId>Server1</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <!-- 集中定义依赖版本号 --> <properties> <junit.version>4.12</junit.version> <spring.version>4.3.8.RELEASE</spring.version> <cxf.version>3.2.6</cxf.version> </properties> <dependencies> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-core</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <version>3.1</version> </configuration> </plugin> <!-- java编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>

    拷贝cxf开发的java工程的代码到web工程中,如图:

    @WebService @BindingType(SOAPBinding.SOAP12HTTP_BINDING) public interface WeatherInterface { public String queryWeather(String cityName); } public class WeatherInterfaceImpl implements WeatherInterface { @Override public String queryWeather(String cityName) { if ("成都".equals(cityName)) { return "冷且霾"; } else { return "暖且晴"; } } }

    配置Spring配置文件 applicationContext.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" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> <!--jaxws:server发布SOAP协议的服务 ,对JaxWsServerFactoryBean类封装 --> <!-- 发布一个服务 id="aa":表示惟一标识 address:表示发布服务的项目地址,weatherServer此时就表示访问url的时候,在?wsdl之前要存在weatherServer,也就是weatherServer?wsdl serviceClass:表示指定发布服务的接口的路径 --> <jaxws:server serviceClass="com.webservice.demo.WeatherInterface" address="/weather"> <jaxws:serviceBean> <ref bean="weatherInterface" /> </jaxws:serviceBean> <!--配置拦截器 --> <jaxws:inInterceptors> <ref bean="inInterceptor" /> </jaxws:inInterceptors> <jaxws:outInterceptors> <ref bean="outInterceptor" /> </jaxws:outInterceptors> </jaxws:server> <!-- 配置服务实现类 --> <bean name="weatherInterface" class="com.webservice.demo.WeatherInterfaceImpl"></bean> <!--配置拦截器bean --> <bean name="inInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/> <bean name="outInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> </beans>

    第五步:配置web.xml

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>D</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 添加Spring的上下文环境监听 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置CXF的Servlet --> <servlet> <servlet-name>CXF</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CXF</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> </web-app>

    第六步:启动tomcat,部署web工程到tomcat 第七步:测试服务是否发布成功

    WSDL地址规则:http://localhost:端口号/项目名称/servlet拦截路径/服务名称?wsdl 客户端程序 第一步:创建web工程作为客户端,引入cxf的jar包 第二步:生成客户端代码

    执行命令:wsdl2java -p 包名 -d . 服务说明书地址 示例: wsdl2java -p com.webservice.client -d . http://localhost:8080/Server1/ws/weather?wsdl

    第三步:配置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:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> <!--jaxws:client实现客户端配置,对JaxWsProxyFactoryBean类封装 --> <jaxws:client id="weatherClient" address="http://127.0.0.1:8080/Server1/ws/weather" serviceClass="com.webservice.client.WeatherInterface"></jaxws:client> </beans>

    第四步:初始化spring上下文,获取接口实现类,调用查询方法

    public class WeatherClient { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); WeatherInterface weatherInterface = (WeatherInterface) context.getBean("weatherClient"); System.out.println(weatherInterface.queryWeather("北京")); } }

    CXF发布REST服务

    什么是REST

    定义:REST就是一种编程风格,它可以精确定位网上资源(服务接口、方法、参数)REST支持数据格式:XML、JSONREST支持发送方式:GET,POST

     需求

    第一个:查询单个学生第二个:查询多个学生

    实现

    服务端 开发步骤:

    导入jar创建学生类,需要加入@ XmlRootElement @XmlRootElement(name="student")//@XmlRootElement可以实现对象和XML数据之间的转换 public class Student { private long id; private String name; private Date birthday; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } } 创建SEI接口 @WebService @Path("/student")//@Path("/student")就是将请求路径中的“/student”映射到接口上 public interface StudentInterface { /** * 根据id查询单个学生 * @param id * @return */ @GET //指定请求方式,如果服务端发布的时候指定的是GET(POST),那么客户端访问时必须使用GET(POST) @Produces(MediaType.APPLICATION_XML_VALUE)//指定服务数据类型 @Path("/query/{id}")//@Path("/query/{id}")就是将"/query"映射到方法上,"{id}"映射到参数上,多个参数,以“/”隔开,放到“{}”中 public Student queryStuById(@PathParam("id")long id); /** * 根据查询多个学生 * @param name * @return */ @GET @Produces({MediaType.APPLICATION_XML_VALUE,"application/json;charset=utf-8"}) @Path("/querylist/{name}") public List<Student> queryStudentList(@PathParam("name") String name); } 创建SEI接口实现类 public class StudentInterfaceImpl implements StudentInterface { @Override public Student queryStuById(long id) { Student st = new Student(); st.setId(id); st.setName("张三"); st.setBirthday(new Date()); return st; } @Override public List<Student> queryStudentList(String name) { Student st = new Student(); st.setId(110); st.setName("张三"); st.setBirthday(new Date()); Student st2 = new Student(); st2.setId(120); st2.setName("李四"); st2.setBirthday(new Date()); List<Student> list = new ArrayList<Student>(); list.add(st); list.add(st2); return list; } } 发布服务 public class StudentServer { public static void main(String[] args) { // JAXRSServerFactoryBean发布REST的服务 JAXRSServerFactoryBean factoryBean = new JAXRSServerFactoryBean(); // 设置服务实现类 factoryBean.setServiceBean(new StudentInterfaceImpl()); // 设置资源类,如果有多个资源类,可以以“,”隔开。 factoryBean.setResourceClasses(StudentInterfaceImpl.class); // 设置服务地址 factoryBean.setAddress("http://localhost:8888/user"); // 发布服务 factoryBean.create(); System.out.println("服务已经发布....."); } } 测试服务

    测试查询单个学生:http://localhost:8888/user/student/query/1002 结果如下:

    <student> <birthday>2017-11-19T21:39:18.449+08:00</birthday> <id>1002</id> <name>张三</name> </student>

    测试查询多个学生:http://localhost:8888/user/student/querylist/1002 GET请求默认是xml类型: 结果如下:

    <students> <student> <birthday>2017-11-19T21:40:16.609+08:00</birthday> <id>110</id> <name>张三</name> </student> <student> <birthday>2017-11-19T21:40:16.609+08:00</birthday> <id>120</id> <name>李四</name> </student> </students>

    多个类型选择:http://localhost:8888/user/student/querylist/1002?_type=json 结果如下:

    {"student":[ {"birthday":"2017-11-19T21:41:28.204+08:00","id":110,"name":"张三"}, {"birthday":"2017-11-19T21:41:28.204+08:00","id":120,"name":"李四"} ] } http://localhost:8888/user/student/querylist/1002?_type=xml

    备注: 如果服务端发布时指定请求方式是GET(POST),客户端必须使用GET(POST)访问服务端,否则会报异常 如果在同一方法上同时指定XML和JSON媒体类型,默认返回XML

    客户端

    public class HttpClient { public static void main(String[] args) throws Exception { System.out.println("haha"); // 第一步:创建服务地址,不是WSDL地址 URL url = new URL("http://localhost:8888/user/student/querylist/1002?_type=json"); // 第二步:打开一个通向服务地址的连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // 第三步:设置参数 // 3.1发送方式设置:POST必须大写 connection.setRequestMethod("GET"); // Post 请求不能使用缓存 connection.setUseCaches(false); connection.setInstanceFollowRedirects(true); // 3.2设置数据格式:content-type // 3.3设置输入输出,因为默认新创建的connection没有读写权限, connection.setDoInput(true); connection.setDoOutput(true); // 第五步:接收服务端响应,打印 int responseCode = connection.getResponseCode(); if (200 == responseCode) {// 表示服务端响应成功 InputStream is = connection.getInputStream(); InputStreamReader isr = new InputStreamReader(is,"UTF-8"); BufferedReader br = new BufferedReader(isr); StringBuilder sb = new StringBuilder(); String temp = null; while (null != (temp = br.readLine())) { sb.append(temp); } System.out.println(sb.toString()); // dom4j解析返回数据,课下作业 is.close(); isr.close(); br.close(); } } }

    CXF+Spring整合REST服务

    服务端

    开发步骤: 第一步:创建web项目(引入jar包)额外的 引入REST所依赖的包

    <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxrs</artifactId> <version>3.2.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-json-provider</artifactId> <version>2.4.1</version> </dependency> <dependency> <groupId>javax.ws.rs</groupId> <artifactId>jsr311-api</artifactId> <version>1.1.1</version> </dependency>

    创建POJO类(同上)

    @XmlRootElement(name="student")//@XmlRootElement可以实现对象和XML数据之间的转换 public class Student { private long id; private String name; private Date birthday; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }

    创建SEI接口(同上)

    @WebService @Path("/student")//@Path("/student")就是将请求路径中的“/student”映射到接口上 public interface StudentInterface { /** * 根据id查询单个学生 * @param id * @return */ @GET //指定请求方式,如果服务端发布的时候指定的是GET(POST),那么客户端访问时必须使用GET(POST) @Produces(MediaType.APPLICATION_XML_VALUE)//指定服务数据类型 @Path("/query/{id}")//@Path("/query/{id}")就是将"/query"映射到方法上,"{id}"映射到参数上,多个参数,以“/”隔开,放到“{}”中 public Student queryStuById(@PathParam("id")long id); /** * 根据查询多个学生 * @param name * @return */ @GET @Produces({MediaType.APPLICATION_XML_VALUE,"application/json;charset=utf-8"}) @Path("/querylist/{name}") public List<Student> queryStudentList(@PathParam("name") String name); }

    创建SEI实现类(同上)

    public class StudentInterfaceImpl implements StudentInterface { @Override public Student queryStuById(long id) { Student st = new Student(); st.setId(id); st.setName("张三"); st.setBirthday(new Date()); return st; } @Override public List<Student> queryStudentList(String name) { Student st = new Student(); st.setId(110); st.setName("张三"); st.setBirthday(new Date()); Student st2 = new Student(); st2.setId(120); st2.setName("李四"); st2.setBirthday(new Date()); List<Student> list = new ArrayList<Student>(); list.add(st); list.add(st2); return list; } }

    第五步:配置Spring配置文件,applicationContext.xml 使用 jaxrs:server发布服务:设置1.服务地址;2.服务实现类

    <?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" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> <!-- 发布REST的服务,对JAXRSServerFactoryBean类封装 --> <jaxrs:server address="/user"> <jaxrs:providers> <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" /> </jaxrs:providers> <jaxrs:serviceBeans> <ref bean="studentInterface" /> </jaxrs:serviceBeans> </jaxrs:server> <!-- 配置服务实现类 --> <bean name="studentInterface" class="com.webservice.service.impl.StudentInterfaceImpl"></bean> </beans>

    第六步:配置web.xml

    <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 添加Spring的上下文环境监听 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置CXF的Servlet --> <servlet> <servlet-name>CXF</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CXF</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping>

    第七步:部署到tomcat下,启动tomcat 第八步:测试服务 REST服务的使用说明书地址: http://localhost:8080/Server1/ws/user/student/querylist/2342342?_type=json

    客户端

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>测试页面</title> <script type="text/javascript"> window.onload = function() { document.getElementsByTagName("input")[0].onclick = function() { var xhr; if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } xhr.open("GET","http://localhost:8080/Server1/ws/user/student/querylist/2342342?_type=json"); xhr.send(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { var result = xhr.responseText; var stu = JSON.parse(result); for(var i=0;i<stu.length;i++){ alert(stu[i].id+"--"+stu[i].name+"--"+stu[i].birthday); } } } } }; } </script> </head> <body> <input type="button" value="点击查询" /> </body> </html>

    综合案例-根据手机号查询手机归属地 需求 集成公网手机号归属地查询服务 对外发布自己的手机号归属地查询服务 提供查询界面

    最新回复(0)