java调⽤WebService服务的四种⽅法总结
⽬录
⼀、前⾔
⼆、简介
三、具体解析
第⼀种⽅式,⾸先得下载axis2的jar包,Axis2提供了⼀个wsdl2java.bat命令可以根据WSDL⽂件⾃动产⽣调⽤WebService的代码。
第⼆种RPC ⽅式,强烈推荐。
第三种:利⽤HttpURLConnection拼接和解析报⽂进⾏调⽤。
第四种,利⽤httpclient
总结
⼀、前⾔
本来不想写这个的,因为⽹上类似的是在是太多了。但是想想⾃⼰前⾯段时间⽤过,⽽且以后可能再也没机会⽤了。所以还是记录⼀下吧。我这⼉是以C语⾔⽣成的WebService为例。因为通常来说,两个java端之间的互相通讯没必要写成WebService的⽅式,太⿇烦。除⾮有⼀⽅已经固定了是webService的⽅式(常见于⽜逼的甲⽅)。⽽且就算写成了WebService⽅式两个java端直接调⽤也相对⽐较简单,因为⽤java的话很多规范都是⾃动⽣成好的,⽽其他语⾔就不是这样了,有时候对⽅压根就不是正确的规范,你还不能让对⽅改我觉得webService这个东西常⽤于不同语⾔编写的服务器之间进⾏数据交互。因为是基于WSDL的。我知道的主要的⽅法有以下⼏种(我这⼉全部以C语⾔编写的WebService做优缺点⽐较):
⼆、简介
1、通过axis2将WebService提供的wsdl⽂件⽣成对应的java类,这样就可以相当调⽤本地类⼀样调⽤webService提供的接⼝。
优点:调⽤简单,⽆需⾃⼰编写太多的东西。
缺点:⼤部分情况根据对应的webService⽣成的服务中地址是固定的,不易更改,⽽且⽣成的代码过于庞⼤,不便于阅读。同时必须得有webservice对应的的wsdl⽂件,不太可控。
2、通过RPC⽅式调⽤(推荐使⽤)
优点:⾃⼰编写部分调⽤代码,可灵活更换调⽤的路径,适合分布式部署的服务器,只需要知道webservice服务的⽅法名、命名空间、以及对应的参数就好。
缺点:部分特殊情况下可能可以调⽤成功,但是⽆法获取返回值。稍后会进⾏说明。
3、通过HttpURLConnection进⾏调⽤,可⽤于补充第⼆种⽅法的不⾜之处。
优点:补充RPC⽅式的不⾜,代码编写量较少。
缺点:(C语⾔的WebService服务)⼤部分时候要⾃⼰编写输⼊的报⽂头,⾃⼰解析返回的报⽂。需要事先抓包查看报⽂。
4、通过httpclient调⽤。
和HttpURLConnection原理⼀样,只是⽤不同⽅法实现。优缺点也差不多。
三、具体解析
第⼀种⽅式,⾸先得下载axis2的jar包,Axis2提供了⼀个wsdl2java.bat命令可以根据WSDL⽂件⾃动产⽣调⽤WebService的代码。
wsdl2java.bat命令可以在<Axis2安装⽬录>/bin⽬录中到。如果你配置了环境变量则可以在控制台中⽤⼀下⽅式
环境变量\bin\wsdl2java,具体如下。
%AXIS2_HOME%\bin\wsdl2java -uri d:demo.wsdl -p client -s -o stub
如果没有则⾃⼰键⼊到对应的位置执⾏。wsdl2java -uri d:demo.wsdl -p client -s -o stub
其中,-url是对应WebService的wsdl位置,可以是本地的也可以是⽹络的。-p是指定⽣成的类名。具体参数列表如下:
-o <path> : 指定⽣成代码的输出路径
-a : ⽣成异步模式的代码
-s : ⽣成同步模式的代码
-p <pkg> : 指定代码的package名称
-l <languange> : 使⽤的语⾔(Java/C) 默认是java
-t : 为代码⽣成测试⽤例
-ss : ⽣成服务端代码默认不⽣成
-sd : ⽣成服务描述⽂件 l,仅与-ss⼀同使⽤
-d <databinding> : 指定databingding,例如,adb,xmlbean,jibx,jaxme and jaxbri
-g : ⽣成服务端和客户端的代码
-pn <port_name> : 当WSDL中有多个port时,指定其中⼀个port
-sn <serv_name> : 选择WSDL中的⼀个service
-u : 展开data-binding的类
-r <path> : 为代码⽣成指定⼀个repository
-ssi : 为服务端实现代码⽣成接⼝类
-S : 为⽣成的源码指定存储路径
-
R : 为⽣成的resources指定存储路径
–noBuildXML : 输出中不⽣成l⽂件
–noWSDL : 在resources⽬录中不⽣成WSDL⽂件
–noMessageReceiver : 不⽣成MessageReceiver类
⽣成完后可以在axis2的bin⽬录下到对应的⽂件。⽂件和同类.java⽂件要⼤很多,并且调⽤路径是定死的(标红部分),改起来⿇烦,反正我是不喜欢这种⽅式。虽然不要⾃⼰写,但是看着这么多⾏就不爽,太臃肿了。
调⽤⽅式如下。(⽅式应该有多种,没有去深⼊研究)
package client;
l.namespace.QName;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.rpc.client.RPCServiceClient;
public class TestAms {
public static void main(String[] args) throws Exception
{
AmsStub1 stub=new AmsStub1();
AmsStub1.SetAlarmServerCfgMsg setmsg= new AmsStub1.SetAlarmServerCfgMsg();
/
/ServiceStub.SetAlarmServerCfgMsgResponse re=new ServiceStub.SetAlarmServerCfgMsgResponse();
String str="{\"name\":\"demo\",\"id\":21,\"code\":\"161021021040288690\"}";//对应的参数
setmsg.setPAlarmCfgMsg(str); //设置参数
String re=stub.setAlarmServerCfgMsg(setmsg).getResponse(); //调⽤并获取返回值
System.out.println(re);
}
}
我⼯作中遇到的全是C语⾔编写的WebService,⽽且每个⼈编写的都有些区别,很多⼈给你的wsdl并不能直接成功⽣成对应的java类,⽽且这种⽅法还有上述的⼀些缺点,所以我抛弃了这种⽅法。(上述列的代码全是以前试验时⽤过的,那时候是成功的,写这个博客的时候我把所有能到的wsdl全试着⽣成⼀遍,结果全部⽣成失败。⼼塞)。
第⼆种RPC ⽅式,强烈推荐。
这种⽅式不多说,直接看代码就懂了。这是⼀个调⽤webService查询设备在线数的。
public String getOnline(String url){
int errCode=0;
JSONObject resultJson=new JSONObject();
String result="";
Service service = new Service();
Call call;
try {
call=(Call) ateCall();
QName opAddEntry = new QName("urn:demo", "GetOnlineInfo"); //设置命名空间和需要调⽤的⽅法名
call.setTargetEndpointAddress(url); //设置请求路径
call.setOperationName("GetNcgOnlineInfo"); //调⽤的⽅法名
call.setTimeout(Integer.valueOf(2000)); //设置请求超时
call.setReturnType(org.ding.XMLType.XSD_STRING);//设置返回类型
result= (String) call.invoke(opAddEntry,new Object[]{});
} catch (ServiceException e) {
// TODO Auto-generated catch block
System.out.println("查询在线状态1:"+e.getMessage());
errCode=1;
} catch (RemoteException e) {
// TODO Auto-generated catch block
System.out.println("查询在线状态2:"+e.getMessage());
errCode=2;
}
resultJson.put("errCode", errCode);
resultJson.put("data", result);
String();
}
⾥⾯注释⽐较全。还有些别的设置也⽐较简单,⾃⼰琢磨就知道了。例如编码⽅式、解析时间等。
说说这种⽅式的问题吧。我在使⽤的时候遇到的是:和我对接的⼈编写了两个WebService。但是由于这两个中有许多部分是相同的,他就把这两个合并了,同时提供了两个命名空间(具体怎么操作的我也不清楚),那么问题了,这其中有⼀个命名空间的所有⽅法我都能成功调⽤,但是都⽆法收到返回值。当时我就⽅了,开始还是好好的,怎么就突然不⾏了,于是我继续执⾏,查看报错消息,同时抓包查看报⽂内容。终于给我发现了问题。
下图是返回结果报的错,⼤体意识就是说我设置的命名空间和对⽅的命名空间不匹配。然后RPC解析就失败了。
然后我利⽤Wireshark抓包,得到⼀下结果。可以看看出,我请求的是命名空间是 ns1="urn:ncg"(其余的都是wsdl默认⾃带的)。可是我收到的返回报⽂就变了。变成了这样的
xmlns:dag="/dag.xsd" xmlns:dag="urn:dag" xmlns:ncg="urn:ncg" ⾜⾜有三个啊。RPC按照默认设置的 ns1="urn:ncg" 去解析,那肯定什么都解析不了的。所以只有⾃⼰去解析了。这种
情况可以利⽤第三种或者第四种⽅式进⾏调⽤。
第三种:利⽤HttpURLConnection拼接和解析报⽂进⾏调⽤。
还是上⾯那个查询设备的⽅法。只不过改了下。当然,我这是知道报⽂后的解决办法。
public String ncgConnection(String url,String method){
URL wsUrl;
int errCode=0;
JSONObject resultJson=new JSONObject();
String result="";
try {
wsUrl = new URL(url+"/"+method);
HttpURLConnection conn = (HttpURLConnection) wsUrl.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
conn.setConnectTimeout(2000);
conn.setReadTimeout(2000);
OutputStream os = OutputStream();
//请求体
//<soapenv:Envelope xmlns:soapenv="/soap/envelope/" xmlns:xsd="/2001/XMLSchema" xmlns:xsi="/2001/XMLSchema-instance"><soapenv:Body><ns1:DeleteCascadeFromCms soapen String soap = "<soapenv:Envelope xmlns:soapenv=\"/soap/envelope/\" xmlns:xsd=\"/2001/XMLSchema\" "
+ "xmlns:xsi=\"/2001/XMLSchema-instance\"><soapenv:Body><ns1:"+method+" soapenv:encodingStyle=\"/soap/encoding/\" xmlns:ns1=\"urn:ncg\"/></soapenv:Body></soapenv:Envelope>";
os.Bytes());
InputStream is = InputStream();
byte[] b = new byte[1024];
int len = 0;
String s = "";
while((len = is.read(b)) != -1){
String ss = new String(b,0,len,"UTF-8");
s += ss;
}
result=s.split("<response xsi:type=\"xsd:string\">")[1].split("</response>")[0];
is.close();
os.close();
conn.disconnect();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
System.out.println("通讯模块1:"+e.getMessage());
errCode=1;
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("通讯模块2:"+e.getMessage());
调用webservice服务errCode=2;
}
resultJson.put("errCode", errCode);
resultJson.put("data", result);
String();
}
正常来说,利⽤HttpURLConnection实现很多的调⽤不需要⾃⼰拼接请求头和解析返回结果的(例如java端提供的⼀些action或者controller),可是在这⼉调⽤WebService,确确实实的需要⾃⼰⼿写。
对⽐上⾯那个Wireshark抓包的结果可以发现,在请求体部分按照对⽅提供的wsdl进⾏拼接,结果部分也进⾏相同的解析。可以正确获得结果。
第四种,利⽤httpclient
简单来说,httpClient可以算是加强版的HttpURLConnection,httpClient的API⽐较多,也⽐较稳定,
不容易扩展。HttpURLConnection⽐较轻量级,容易根据⾃⼰的需求进⾏扩展。但是稳定性不如httpClient。
这种⽅法具体实现思路和HttpURLConnection⼀样。只是有点⼩区别。代码如下:
public void demo(String url){
HttpClient httpClient=new HttpClient();
PostMethod postMethod=new PostMethod();
postMethod.setPath(url+"/ncg.wsdl"); //路径和wsdl名
String soap = "<soapenv:Envelope xmlns:soapenv=\"/soap/envelope/\" xmlns:xsd=\"/2001/XMLSchema\" "
+ "xmlns:xsi=\"/2001/XMLSchema-instance\"><soapenv:Body><ns1:GetNcgOnlineInfo soapenv:encodingStyle=\"/soap/encoding/\" xmlns:ns1=\"urn:ncg\"/></soapenv:Body></soapenv:Envelope>"; try {
byte[] Bytes("utf-8");
InputStream is = new ByteArrayInputStream(b, 0, b.length);
RequestEntity re = new InputStreamRequestEntity(is, b.length,
"application/soap+xml; charset=utf-8");
postMethod.setRequestEntity(re);
int statusCode = uteMethod(postMethod);
String soapResponseData = ResponseBodyAsString();
//解析
System.out.println(soapResponseData.split("<response xsi:type=\"xsd:string\">")[1].split("</response>")[0]);
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
结果:我这⼉没有做更多的判断,直接输出,这种⽅式我以前其实并没有⽤到。如果有需要可以更具返回的状态判断是否成功。如果你去抓包的话,你会发现这个会和上⾯HttpURLConnection抓的⼀样。
总结:调⽤webService很多程度上需要依赖对⽅编写WebService是否严谨,如果⾜够严谨,推荐使⽤RPC⽅式编写,其余的更具实际情况进⾏选择
总结
到此这篇关于java调⽤WebService服务的四种⽅法的⽂章就介绍到这了,更多相关java调⽤WebService服务内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论