首页 > 实战CXF调用Webxml天气预报服务

凡客体在线生成,实战CXF调用Webxml天气预报服务

互联网 2021-03-07 01:17:33

实战CXF调用Webxml天气预报服务

今晚群里的kasasis同学问我会不会使用CXF调用

http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

这个天气预报的WebService服务;

我也是初学者, 在尝试调用的过程中发现不少问题, 也有一些小心得, 希望与大家分享, 更希望大家可以帮我解惑.

一.初探:通过wsdl2java生成调用远程服务所需要的java类

因为还没有成功使用dynamic-clients(http://cxf.apache.org/docs/dynamic-clients.html)的方式动态调用过WebService服务, 所以决定使用CXF提供的wsdl2java来生成调用WebService服务所必须的java类, 进而使用JaxWsServerFactoryBean来调用WebService服务:

wsdl2java 天气预报的wsd时出错

遗憾的是, CXF wsdl2java报错了:

 

undefined element declaration 's:schema'at line 85 column 41 of schema

 http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

将该wsdl下载下来, 使用MyEclipse 9.0打开并查看, 也提示了这一错误:

src-resolve.4.2: Error resolving component 's:schema'. It was detected that 's:schema' is in namespace 'http://www.w3.org/2001/XMLSchema', but components from this namespace are not referenceable from schema document 'file:///D:/workspace/workspace_j2ee/CXFWeatherTest/src/WeatherWebService.asmx.original.wsdl'. If this is the incorrect namespace, perhaps the prefix of 's:schema' needs to be changed. If this is the correct namespace, then an appropriate 'import' tag should be added to 'file:///D:/workspace/workspace_j2ee/CXFWeatherTest/src/WeatherWebService.asmx.original.wsdl'.

wsdl报错部分内容如下(下边代码红色部分):

                                                 

作为初学者, 曾在风中叶老师的视频中学习过关于schema及DTD的一些知识, 但还没修炼到能解决这一错误的程度, 也期待各位同学的积极探索并给出答案;

问题催人奋进, 折衷的办法总是有的:

既然可以代表任何元素, 为什么不能代表元素呢? 于是乎, 愤然删除, 勉强算是通过了CXF提供的wsdl验证工具wsdlvalidator的验证;

Ok, 继续之前的步骤, 通过wsdl2java来生成调用远程WebService服务所需要的java类;

一切顺利, 生成的类的目录结构如下:

  wsdl2java天气服务webService的wsdl后产生的客户端调用java类

二.使用JaxWsProxyFactoryBean调用天气服务

本工程使用的jar包如下图示:

工程使用的jar包

通过JaxWsProxyFactoryBean调用webService服务的过程相信大家都很熟悉了, 具体代码如下:

package cn.com.client;import java.util.List;import org.apache.cxf.interceptor.LoggingInInterceptor;import org.apache.cxf.interceptor.LoggingOutInterceptor;import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;import cn.com.webxml.ArrayOfString;import cn.com.webxml.WeatherWebServiceSoap;public class Test {    public static void main(String[] args) throws Exception {        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();        factory.getInInterceptors().add(new LoggingInInterceptor());        factory.getOutInterceptors().add(new LoggingOutInterceptor());         factory.setAddress(                "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx");        factory.setServiceClass(WeatherWebServiceSoap.class);         WeatherWebServiceSoap client =                (WeatherWebServiceSoap) factory.create();        ArrayOfString o = client.getWeatherbyCityName("南阳");        List strList = o.getString();        for (String str : strList) {            System.out.println(str);        }    }}

 运行还算顺利, 得到的结果如下:

信息: Outbound Message

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

ID: 1

Address: http://www.webxml.com.cn/WebServices/WeatherWebService.asmx

Encoding: UTF-8

Content-Type: text/xml

Headers: {Accept=[*/*], SOAPAction=["http://WebXml.com.cn/getWeatherbyCityName"]}

Payload:

南阳

河南

南阳

57178

57178.jpg

2012-4-5 22:58:11

11℃/24℃

4月6日 晴

无持续风向微风

0.gif

0.gif

今日天气实况:气温:16℃;风向/风力:北风 0级;湿度:53%;空气质量:较差;紫外线强度:中等

穿衣指数:建议着薄型套装等春秋过渡装。年老体弱者宜着套装。但昼夜温差较大,注意适当增减衣服。

感冒指数:昼夜温差较大,较易发生感冒,请适当增减衣服。体质较弱的朋友请注意防护。

运动指数:天气较好,赶快投身大自然参与户外运动,尽情感受运动的快乐吧。

洗车指数:适宜洗车,未来持续两天无雨天气较好,适合擦洗汽车,蓝天白云、风和日丽将伴您的车子连日洁净。

晾晒指数:天气不错,适宜晾晒。赶紧把久未见阳光的衣物搬出来吸收一下太阳的味道吧!

旅游指数:天气晴朗,风和日丽,温度适宜,是个好天气哦。这样的天气很适宜旅游,您可以尽情地享受大自然的风光。

路况指数:天气较好,路面比较干燥,路况较好。

舒适度指数:温度适宜,风力不大,您在这样的天气条件下,会感到比较清爽和舒适。

空气污染指数:气象条件较不利于空气污染物稀释、扩散和清除,请适当减少室外活动时间。

紫外线指数:属中等强度紫外线辐射天气,外出时建议涂擦SPF高于15、PA+的防晒护肤品,戴帽子、太阳镜。

11℃/24℃

4月7日 晴

无持续风向微风

0.gif

0.gif

10℃/23℃

4月8日 阴转多云

无持续风向微风

2.gif

1.gif

南阳市位于河南省西南部,北靠伏牛山,东扶桐柏山,西依秦岭,南临汉江。气候属南北过渡带,四季分明。这里土地肥沃,雨量充沛。现辖1市2区10县,总面积2.66万平方公里,人口1055万。南阳是历史文化名城。早在“南召猿人”就在这里生息繁衍。战国时期,是全国著名的冶铁中心,西汉时为全国六大都会之一,“商遍天下,富冠海内”,东汉为光武帝刘秀发迹之地,故称“南都…‘帝乡”。南阳曾培养和造就出著名谋略家、商圣”范蠢,“科圣”张衡,“医圣”张仲景,杰出的政治家、军事家诸葛亮等举世间名的历史人物。1948年,毛泽东主席为庆祝南阳解放,亲笔写下《中原我军占领南阳》的光辉篇章。今日的南阳,是一座现代化新城。南阳市中心城区建成区面积为40平方公里,人口43万。城市环境优美,街道清洁宽敞,高楼大厦林立。北京大道、工业路、人民路、新华路等主于道纵横交错,道路成网;南阳宾馆。梅溪宾馆、豫宛宾馆等各类星级宾馆为八方宾客提供优美舒适的服务;南阳商场、金汉丰商厦、南阳亚细亚商厦等大型购物中心,向海内外朋友显示出南阳商贸发达的新景象。被称为中国之最的南阳沼气工程,日产沼气40万立方米,可满足2万用户居民用气。全市具有较高审美价值和文化价值的名胜古迹40多处,每天吸引着大量中外游人。景观:武候祠,内乡,天心洞,内乡县衙,张仲景墓与医圣祠张衡墓,汉画像石馆,桐柏淮源,宝天墁自然保护区,九龙沟,丹江口水库,西峡,伏牛山,水帘洞,白河

三.使用JaxWsDynamicClientFactory调用天气服务

CXF关于Dynamic-clients的介绍文档见:

http://cxf.apache.org/docs/dynamic-clients.html;

很简洁的一段官方示例代码:

JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient("echo.wsdl"); Object[] res = client.invoke("echo", "test echo"); System.out.println("Echo response: " + res[0]);

但具体的调用过程并非一帆风顺; 让人不解的是, 即使调用自己所创建的WebService, 使用动态方式调用也不能成功, 总会提示一个异常:

Exception in thread "main" java.lang.IllegalStateException: Unable to write generated Java files for schemas: null at org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:351) at org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:234) at org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:227) at org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:182) at com.client.Test.dynamicStudent(Test.java:30) at com.client.Test.main(Test.java:38) Caused by: java.lang.reflect.UndeclaredThrowableException at $Proxy29.build(Unknown Source) at org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:349) ... 5 more Caused by: java.lang.NoSuchMethodException: com.sun.codemodel.internal.JCodeModel.build(java.lang.Object) at java.lang.Class.getMethod(Class.java:1605) at org.apache.cxf.common.util.ReflectionInvokationHandler.invoke(ReflectionInvokationHandler.java:50) ... 7 more

异常信息的最后一个Caused by给了我线索:

java.lang.NoSuchMethodException: 

com.sun.codemodel.internal.JCodeModel.build(java.lang.Object)

遍历工程所用jar文件, 居然没有找到internal包下的类JCodeModel;

但报的异常是NoSuchMethodException, 而不是ClassNotFoundException, 表明该类是存在的, 可能包路径发生了变化, 遂STFG(search the fUcking google. 从陈皓老师的博文学到的 - - 囧), 最终发现该类现存在于jaxb-xjc-2.2.4-1.jar中, 包路径为com.sun.codemodel, 而不是异常中所提示的com.sun.codemodel.internal;

为什么会这样? 难道是我的jaxb-xjc jar包的版本不对? 

遂通过http://jaxb.java.net/, 对比jaxb2.0.1 -- 2.2.5之间的所有版本, 均没有找到包com.sun.codemodel.internal...

Ok, 让我们继续查找jaxb1.x版本的jar包;

幸运的是, 在页面http://jaxb.java.net/nonav/2.0.1/docs/jaxb-1_0.html , 终于有所发现:

JAXB 2.0 is backwards compatible with JAXB 1.0 - you can deploy your existing 1.0 applications on the 2.0 runtime (provided that you also bundle the jaxb1-impl.jar) and they should run without modification. 

查看我的项目的类库, 刚好缺少了这么一个jaxb-impl.jar包,,, 加上该包(我使用的是jaxb-impl-2.2.4-1.jar), 再次运行动态调用天气预报WebService的服务, Congratulations! 这个异常被干掉了! 

但是, 不要高兴的太早, 服务并没有调用成功, 因为又回到了最开始遇到的问题:

,

undefined element declaration 's:schema'

 at line 85 column 41 of schema 

http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

具体调用代码如下:

package com.client; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class Test {     public static void main(String[] args) throws Exception {         JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();         Client client = dcf.createClient(             "http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl");         Object[] res = client.invoke("getSupportProvince");         System.out.println("Echo response: " + res[0]);     } }

值得欣慰的是, 在补充了jaxb-impl-2.2.4-1.jar之后, 可以通过动态方式成功调用自己创建的WebService服务了, 详见下节;

四.使用JaxWsDynamicClientFactory动态调用自己创建的WebService服务

服务接口及实现类很简单:

接口 com.service.StudentService:

package com.service; import javax.jws.WebParam; import javax.jws.WebService; @WebService public interface StudentService {     String helloStudent(@WebParam(name="text")String name); }

实现类 com.service.impl.StudentServiceImpl:

package com.service.impl; import javax.jws.WebService; import com.service.StudentService; @WebService(endpointInterface="com.service.StudentService", targetNamespace="http://service.com/") public class StudentServiceImpl implements StudentService{     public String helloStudent(String name) {         return "hello " + name;     } }

server类: com.jettyServer.ServerForJetty:

package com.jettyServer; import javax.xml.ws.Endpoint; import com.service.impl.StudentServiceImpl; public class ServerForJetty {     public static void main(String[] args) throws InterruptedException {         StudentServiceImpl implementor = new StudentServiceImpl();         String address = "http://localhost:9000/student";         Endpoint.publish(address, implementor);     } }

client类:com.client.Test 

package com.client; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class Test {     public static void main(String[] args) throws Exception {         JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();                  Client client = dcf.createClient("http://localhost:9000/student?wsdl");         Object[] res = client.invoke("helloStudent", "LeeThinker");         System.out.println("Echo response: " + res[0]);     } }

先启动JettyServer, 后访问http://localhost:9000/student?wsdl, 成功刷新出wsdl, Ok, 服务顺利启动!

再执行Test的main方法, Congratulations! 这次真正使用Dynamic的方式, 在不需要通过wsdl2java生成客户端java类文件的情况下, 成功调用WebService服务!

至于不能通过这种方式成功调用

http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

的问题, 还需要在进一步学习Schema和DTD的知识才能解答;

五.小结:

虽未能通过Dynamic的方式成功调用天气预报服务, 好歹wsdl2java生成客户端调用类

的方式是可行的.

六.其他问题: 6.1.@WebService声明问题

在"四.使用JaxWsDynamicClientFactory调用自己创建的WebService服务"中

自定义服务接口的实现类com.service.impl.StudentServiceImpl的类声明之前, 仅注释声明了@WebService, 而没有后边的(endpointInterface="com.service.StudentService", 

targetNamespace="http://service.com/"), 这时使用动态代理方式调用该服务时, 会发生异常:

Exception in thread "main" 

org.apache.cxf.common.i18n.UncheckedException: No operation was  found with the name {http://impl.service.com/}helloStudent.

大概还是因为WSDL的基础知识不够过硬吧, STFG后, 在

http://lost-alien.iteye.com/blog/1175859 找到答案:

@WebService注释的学问?

在com.service.impl.StudentServiceImpl的类声明之前, 正确注释了

@WebService(

endpointInterface="com.service.StudentService",  targetNamespace="http://service.com/")之后,

再使用动态方式调用该服务, 一切顺利!

具体原因还有待分析, 认识和理解!

6.2.关于CXF wsdl2java生成的调用远程服务的客户端java类文件

在"四.使用JaxWsDynamicClientFactory调用自己创建的WebService服务"中所描述的自定义WebService服务中, 若使用JaxWsServerFactoryBean的调用方式, 那么首先需要通过wsdl2java生成客户端必需的java类文件;

将通过自己的wsdl生成的客户端java类文件的目录结构&类名称, 

和wsdl2java http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl 

这个wsdl文件后生成的java类文件的目录结构&类名称, 对比之后, 发现差距明显:

为什么我的类, 命名这么凌乱?

对比可以清楚的看到, 自己的wsdl生成的客户端类文件, 其java类文件名及其混乱, 始终没能弄懂为什么会这样? 还请各位同学多多指教! 

七.联系.讨论

我的QQ: 17.37.045.23, 邮箱: windwalk#live.cn, 欢迎来自你的交流和讨论! 谢谢!

CXF和WebService的学习过程充满着各种困难, 还希望同学们可以广泛交流, 相互帮

助, 共同进步!

最后, 借用陈皓老师的技术微博上转发的"凡客体"来自勉:

爱学习, 爱编程, 爱咖啡可乐!

爱挑战, 爱钻研, 爱打游戏!

爱晚期, 也爱工作到深夜!

我擅长技术, 崇尚简单和懒惰!

我神秘而孤僻, 沉默而爱憎分明!

我行我素, 我是程序员!

(原文链接:http://coolshell.cn/articles/2806.html)

程序员之

免责声明:非本网注明原创的信息,皆为程序自动获取自互联网,目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责;如此页面有侵犯到您的权益,请给站长发送邮件,并提供相关证明(版权证明、身份证正反面、侵权链接),站长将在收到邮件24小时内删除。