实战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服务:
遗憾的是,CXFwsdl2java报错了:
1
|
undefined
element declaration 's:schema'
|
3
|
at
line 85 column 41 of schema
|
http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
将该wsdl下载下来,使用MyEclipse9.0打开并查看,也提示了这一错误:
1
|
src-resolve. 4.2 :
Error resolving component 's:schema' .
|
3
|
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' .
|
5
|
If this is
the incorrect namespace, perhaps the prefix of 's:schema' needs
to be changed.
|
7
|
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报错部分内容如下(下边代码红色部分):
01
|
< s:element name = "getSupportDataSetResponse" >
|
13
|
name = "getSupportDataSetResult" >
|
1
|
< s:element ref = "s:schema" />
|
作为初学者,曾在风中叶老师的视频中学习过关于schema及DTD的一些知识,但还没修炼到能解决这一错误的程度,也期待各位同学的积极探索并给出答案;
问题催人奋进,折衷的办法总是有的:
<s:any/>既然可以代表任何元素,为什么不能代表<s:elementref="xxx"/>元素呢?于是乎,愤然删除<s:elementref="s:schema"/>,勉强算是通过了CXF提供的wsdl验证工具wsdlvalidator的验证;
Ok,继续之前的步骤,通过wsdl2java来生成调用远程WebService服务所需要的java类;
一切顺利,生成的类的目录结构如下:
二.使用JaxWsProxyFactoryBean调用天气服务
本工程使用的jar包如下图示:
通过JaxWsProxyFactoryBean调用webService服务的过程相信大家都很熟悉了,具体代码如下:
05
|
import org.apache.cxf.interceptor.LoggingInInterceptor;
|
07
|
import org.apache.cxf.interceptor.LoggingOutInterceptor;
|
09
|
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
|
11
|
import cn.com.webxml.ArrayOfString;
|
13
|
import cn.com.webxml.WeatherWebServiceSoap;
|
17
|
public static void main(String[]
args) throws Exception
{
|
19
|
JaxWsProxyFactoryBean
factory = new JaxWsProxyFactoryBean();
|
21
|
factory.getInInterceptors().add( new LoggingInInterceptor());
|
23
|
factory.getOutInterceptors().add( new LoggingOutInterceptor());
|
27
|
"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx" );
|
29
|
factory.setServiceClass(WeatherWebServiceSoap. class );
|
31
|
WeatherWebServiceSoap
client =
|
33
|
(WeatherWebServiceSoap)
factory.create();
|
35
|
ArrayOfString
o = client.getWeatherbyCityName( "南阳" );
|
37
|
List<String>
strList = o.getString();
|
39
|
for (String
str : strList) {
|
41
|
System.out.println(str);
|
运行还算顺利,得到的结果如下:
信息:OutboundMessage
---------------------------
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:
<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getWeatherbyCityNamexmlns="http://WebXml.com.cn/">
<theCityName>南阳</theCityName>
</getWeatherbyCityName>
</soap:Body>
</soap:Envelope>
河南
南阳
57178
57178.jpg
2012-4-522: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;
很简洁的一段官方示例代码:
1
|
JaxWsDynamicClientFactory
dcf = JaxWsDynamicClientFactory.newInstance();
|
3
|
Client
client = dcf.createClient( "echo.wsdl" );
|
5
|
Object[]
res = client.invoke( "echo" , "test
echo" );
|
7
|
System.out.println( "Echo
response: " +
res[ 0 ]);
|
但具体的调用过程并非一帆风顺;让人不解的是,即使调用自己所创建的WebService,使用动态方式调用也不能成功,总会提示一个异常:
01
|
Exception
in thread "main" java.lang.IllegalStateException:
Unable to write generated Java files for schemas: null
|
03
|
at
org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java: 351 )
|
05
|
at
org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java: 234 )
|
07
|
at
org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java: 227 )
|
09
|
at
org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java: 182 )
|
11
|
at
com.client.Test.dynamicStudent(Test.java: 30 )
|
13
|
at
com.client.Test.main(Test.java: 38 )
|
15
|
Caused
by: java.lang.reflect.UndeclaredThrowableException
|
17
|
at
$Proxy29.build(Unknown Source)
|
19
|
at
org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java: 349 )
|
23
|
Caused
by: java.lang.NoSuchMethodException:
|
25
|
com.sun.codemodel.internal.JCodeModel.build(java.lang.Object)
|
27
|
at
java.lang.Class.getMethod(Class.java: 1605 )
|
29
|
at
org.apache.cxf.common.util.ReflectionInvokationHandler.invoke(ReflectionInvokationHandler.java: 50 )
|
异常信息的最后一个Causedby给了我线索:
java.lang.NoSuchMethodException:
com.sun.codemodel.internal.JCodeModel.build(java.lang.Object)
遍历工程所用jar文件,居然没有找到internal包下的类JCodeModel;
但报的异常是NoSuchMethodException,而不是ClassNotFoundException,表明该类是存在的,可能包路径发生了变化,遂STFG(searchthefUckinggoogle.从陈皓老师的博文学到的--囧),最终发现该类现存在于jaxb-xjc-2.2.4-1.jar中,包路径为com.sun.codemodel,而不是异常中所提示的com.sun.codemodel.internal;
为什么会这样?难道是我的jaxb-xjcjar包的版本不对?
遂通过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,终于有所发现:
JAXB2.0isbackwardscompatiblewithJAXB1.0-youcandeployyourexisting1.0applicationsonthe2.0runtime(providedthatyoualsobundlethejaxb1-impl.jar)andtheyshouldrunwithoutmodification.
查看我的项目的类库,刚好缺少了这么一个jaxb-impl.jar包,,,加上该包(我使用的是jaxb-impl-2.2.4-1.jar),再次运行动态调用天气预报WebService的服务,Congratulations!这个异常被干掉了!
但是,不要高兴的太早,服务并没有调用成功,因为又回到了最开始遇到的问题:
<s:elementref="s:schema"/>,
undefinedelementdeclaration's:schema'
atline85column41ofschema
http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
具体调用代码如下:
03
|
import org.apache.cxf.endpoint.Client;
|
05
|
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
|
09
|
public static void main(String[]
args) throws Exception
{
|
11
|
JaxWsDynamicClientFactory
dcf = JaxWsDynamicClientFactory.newInstance();
|
13
|
Client
client = dcf.createClient(
|
15
|
"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl" );
|
17
|
Object[]
res = client.invoke( "getSupportProvince" );
|
19
|
System.out.println( "Echo
response: " +
res[ 0 ]);
|
值得欣慰的是,在补充了jaxb-impl-2.2.4-1.jar之后,可以通过动态方式成功调用自己创建的WebService服务了,详见下节;
四.使用JaxWsDynamicClientFactory动态调用自己创建的WebService服务
服务接口及实现类很简单:
接口com.service.StudentService:
03
|
import javax.jws.WebParam;
|
05
|
import javax.jws.WebService;
|
09
|
public interface StudentService
{
|
11
|
String
helloStudent( @WebParam (name= "text" )String
name);
|
实现类com.service.impl.StudentServiceImpl:
01
|
package com.service.impl;
|
03
|
import javax.jws.WebService;
|
05
|
import com.service.StudentService;
|
07
|
@WebService (endpointInterface= "com.service.StudentService" ,
targetNamespace= "http://service.com/" )
|
09
|
public class StudentServiceImpl implements StudentService{
|
11
|
public String
helloStudent(String name) {
|
server类:com.jettyServer.ServerForJetty:
01
|
package com.jettyServer;
|
03
|
import javax.xml.ws.Endpoint;
|
05
|
import com.service.impl.StudentServiceImpl;
|
07
|
public class ServerForJetty
{
|
09
|
public static void main(String[]
args) throws InterruptedException
{
|
11
|
StudentServiceImpl
implementor = new StudentServiceImpl();
|
13
|
String
address = "http://localhost:9000/student" ;
|
15
|
Endpoint.publish(address,
implementor);
|
client类:com.client.Test
03
|
import org.apache.cxf.endpoint.Client;
|
05
|
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
|
09
|
public static void main(String[]
args) throws Exception
{
|
11
|
JaxWsDynamicClientFactory
dcf = JaxWsDynamicClientFactory.newInstance();
|
1
|
Client
client = dcf.createClient( "http://localhost:9000/student?wsdl" );
|
3
|
Object[]
res = client.invoke( "helloStudent" , "LeeThinker" );
|
5
|
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/"),这时使用动态代理方式调用该服务时,会发生异常:
Exceptioninthread"main"
org.apache.cxf.common.i18n.UncheckedException:Nooperationwasfoundwiththename{http://impl.service.com/}helloStudent.
大概还是因为WSDL的基础知识不够过硬吧,STFG后,在
http://lost-alien.iteye.com/blog/1175859找到答案:
在com.service.impl.StudentServiceImpl的类声明之前,正确注释了
@WebService(
endpointInterface="com.service.StudentService",targetNamespace="http://service.com/")之后,
再使用动态方式调用该服务,一切顺利!
具体原因还有待分析,认识和理解!
6.2.关于CXFwsdl2java生成的调用远程服务的客户端java类文件
在"四.使用JaxWsDynamicClientFactory调用自己创建的WebService服务"中所描述的自定义WebService服务中,若使用JaxWsServerFactoryBean的调用方式,那么首先需要通过wsdl2java生成客户端必需的java类文件;
将通过自己的wsdl生成的客户端java类文件的目录结构&类名称,
和wsdl2javahttp://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
这个wsdl文件后生成的java类文件的目录结构&类名称,对比之后,发现差距明显:
对比可以清楚的看到,自己的wsdl生成的客户端类文件,其java类文件名及其混乱,始终没能弄懂为什么会这样?还请各位同学多多指教!
分享到:
相关推荐
webservice天气预报例子cxf实例,
用框架cxf调用axis2提供的接口服务的一个简单例子,
用camel-cxf调用webservice和发布一个webservice接口例子,首先启动QueryServiceMain主函数启动webservice接口,然后启动测试类TestWebservice。例子主要是实现java代码实现camel调用webservice接口
Spring集成Cxf调用WebServices
cxf客户端调用axis服务端流程
NULL 博文链接:https://liugang594.iteye.com/blog/2022626
java CXF客户端请求ERP SAP webservice通过用户名和密码验证功能!
CXF 开发手册, 包括下载,配置,客户端调用远程服务以及发布自己的接口为服务,供别人调用的全过程
cxf获取第三方天气数据包中内含: MainTest.java, WeatherWS.wsdl,使用说明文档.txt
springboot整合CXF发布webservice和客户端调用 项目中每个类都有详细的注释,保证都能看懂,不失为一个学习springboot整合cxf来学习webservice发布调用的好例子
C#动态调用CXF WEBSERVICE框架共通类。
cxf客户端调用webservice所需jar包
cxf客户端调用axis服务端流程.docxcxf客户端调用axis服务端流程.docx
通过jsp页面动态访问天气预报功能,涉及到的技术有jsp,tomcat,cxf,webservice,servlet,jquery,ajax
java调用c#的webservice,其中包括demo和需要的jar包,下载下来,导入eclipse就可以直接看到main方法。不需要配置什么文件
CXF客户端调用例子,本例子开发语言为JAVA,包内包含服务端跟客户端
Java 调用webservice cxf客户端调用demo和服务端,包含jar包,服务端发布后直接用客户端调用
现在主流的webService框架,一个是axis2,一个是cxf,本资源是基于cxf框架的简单例子
JAVA 用 Apache CXF 调用 .NET 服务端 WebService 代码 整个JAVA工程的压缩,导入到myeclipse可直接运行,如果只想浏览下,请访问:http://blog.csdn.net/wqmain/article/details/8216331
使用spring3+ cxf 3.4做服务方,Axis1.4做请求方,在调用的时候,通过转换cxf的wsdl格式为axis1.4的wsdl格式来达到调用的目的。