写在前面:
调用webservice的方式有很多:1.直接在客户端使用工具生成客户端代码,将代码拷进项目中调用即可;2.使用对应的webservice框架来进行调用,比如如果我们我的服务端开发用的是axis,那么我在客户端也可以导入相应的axis的jar包,然后用它相关的方法来进行调用;3.js调用;4.URLConnection调用。上面的前两种方式个人认为比较适用于服务端与客户端都是java开发系统,如果是不同语言的调用那就不好说了。而第三种与第四种的方式其实差不多,如果在jsp页面中就要调用接口,就用js这种方式,如果需要在后台写程序来调用,就比较推荐URLConnection了(现在只是会用,其实它的一些原理什么的我还是很模糊,比如这种方式应该是http??调用??,还不是很清楚呢)
最近项目要开发webservice接口,但是jdk是1.4。故选择了axis1.4来进行开发(只有这个比较适合项目的环境)。
这里我也是用的java语言来做测试的,是可以调用的。解析服务端返回的数据需要用到相关jar包:
代码:
package edu.hue.client; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.StringReader; import java.net.HttpURLConnection; import java.net.ProtocolException; import java.net.URL; import java.net.URLConnection; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class XMLClient2 { public static void main(String[] args) { try { //创建url地址 URL url = new URL("http://10.203.138.82:8080/test_axis3/services/sayHello?wsdl"); //打开连接 URLConnection conn = url.openConnection(); //转换成HttpURL HttpURLConnection httpConn = (HttpURLConnection) conn; System.setProperty("sun.net.client.defaultConnectTimeout", "30000"); System.setProperty("sun.net.client.defaultReadTimeout", "30000"); //打开输入输出的开关 httpConn.setDoInput(true); httpConn.setDoOutput(true); //post提交不能有缓存 httpConn.setUseCaches(false); //设置请求方式 httpConn.setRequestMethod("POST"); //设置请求的头信息 httpConn.setRequestProperty("Content-type", "text/xml;charset=UTF-8"); //设置 SOAPAction Header 不然 报错 没有这个soapaction header httpConn.setRequestProperty("SOAPAction", ""); //拼接请求消息 这里的请求消息体 直接用接口测试工具 soapui 来获取 然后拼接以下 注意双引号这里要转义成\" String data = "<soapenv:Envelope xmlns:soapenv=" + "\"http://schemas.xmlsoap.org/soap/envelope/\" " + "xmlns:ser=\"http://server.hue.edu/\" " + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" //+"<soapenv:Header />" +"<soapenv:Body>" +"<ser:say soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +"<name xsi:type=\"soapenc:string\" xs:type=\"type:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xs=\"http://www.w3.org/2000/XMLSchema-instance\">" +"小蚊子qq:513996980" //这里是直接在soapui中复制过来的所以它的请求消息体比较长 也可以用下面这种 注释的方式来拼接 +"</name>" +"</ser:say>" +"</soapenv:Body>" +"</soapenv:Envelope>"; /* 下面这种请求消息体更为简单 经过测试也可以成功 它的方法名 参数名 都很简洁 * 但是为了保险 希望大家在写请求消息体的时候用 接口测试工具去获取比如soapui 然后直接复制过来 String data = "<soapenv:Envelope xmlns:soapenv=" + "\"http://schemas.xmlsoap.org/soap/envelope/\" " + "xmlns:ser=\"http://server.hue.edu/\" " + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +"<soapenv:Header />" +"<soapenv:Body>" +"<ser:say >" +"<name>小蚊子qq:513996980</name>" +"</ser:say>" +"</soapenv:Body>" +"</soapenv:Envelope>";*/ //获得输出流 OutputStream out = httpConn.getOutputStream(); //发送数据 这里注意要带上编码utf-8 不然 不能传递中文参数过去 out.write(data.getBytes("UTF-8")); //判断请求成功 if(httpConn.getResponseCode() == 200){ System.out.println("调用成功....."); //获得输入流 InputStream in = httpConn.getInputStream(); //使用输入流的缓冲区 BufferedReader reader = new BufferedReader(new InputStreamReader(in,"UTF-8")); StringBuffer sb = new StringBuffer(); String line = null; //读取输入流 while((line = reader.readLine()) != null){ sb.append(line); } //创建sax的读取器 这里需要导入相应的jar包 SAXReader saxReader = new SAXReader(); //创建文档对象 Document doc = saxReader.read(new StringReader(sb.toString())); //获得请求响应return元素 这里可根据接口测试工具查看你的相应消息体的返回值的节点是什么名称 我这里是sayReturn List eles = doc.selectNodes("//sayReturn"); for(int i=0;i<eles.size();i++){ Element ele = (Element)eles.get(i); System.out.println(ele.getText()); } System.out.println(sb.toString()); }else{ //调用不成功 打印错误的信息 //获得输入流 InputStream err = httpConn.getErrorStream(); //使用输入流的缓冲区 BufferedReader reader = new BufferedReader(new InputStreamReader(err,"UTF-8")); StringBuffer sb = new StringBuffer(); String line = null; //读取输入流 while((line = reader.readLine()) != null){ sb.append(line); } System.out.println("返回错误码:"+httpConn.getResponseCode()); System.out.println("返回的结果:"+sb.toString()); } } catch (Exception e) { e.printStackTrace(); } } }
上面是客户端调用的代码,服务端这里就不多贴了,就只是一个方法,里面有一个String类型的参数。
问题总结:
1.报错误 说http response result code 500:
java.io.IOException: Server returned HTTP response code: 500 for URL: http://10.203.138.82:8080/test_axis/services/sayHello
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1626)
这里的500错误 一般都是你的代码有问题 哪里可能写的有点不对 这个时候就要仔细仔细再仔细 然后尝试用不同的方式去排除错误所在的地方 也要多百度 多查 ,这里我出现这个问题 是因为把输入流写在输出流的前面(对于客户端,应该是先写输出流之后,再写输入流get.InputStream())
2.针对axis1.4的bug:AxisFault faultCode: {http://xml.apache.org/axis/}Client.NoSOAPAction faultSubcode: faultString: no SOAPAction header! faultActor: faultNode: faultDetail: {http://xml.apache.org/axis/}stackTrace:no SOAPAction header!
no SOAPAction header! 这里可以注意 如果报这个错 加上一行代码就好了啦 当初为了这个错误 几乎看了一两天的博客文章 但是却没有人告诉具体的代码解决办法(有两种解决办法1:在客户端加上soapaction,其具体内容不重要,写一个空的字符串也是可以的 2:服务端重写写一个servlet,与axisServlet一样,并重新改写里面的getSoapAction()方法,这里推荐只第一种,毕竟这个也算不上是axis的bug)
//设置 SOAPAction Header 不然 报错 没有这个soapaction header
httpConn.setRequestProperty("SOAPAction", "");
3.如果客户端传递参数为中文就报错:变为字节数组的时候加上UTF-8
//获得输出流
OutputStream out = httpConn.getOutputStream();
//发送数据 这里注意要带上编码utf-8 不然 不能传递中文参数过去
out.write(data.getBytes("UTF-8"));
疑问:
如果方法没有参数 需要怎么调用???在这里 之前 跨平台 调用wcf开发的.net系统的时候 调用的接口方法是不需要传递参数的 但是也传了一个空的字符串过去就好了 也没有写什么soap请求消息体什么的 但是这里因为是webservice 它是基于soap的 所以这里传递数据 不管有没有参数 应该都是要写上消息请求体的 所以这里需要注意一下
比如:
// 但是为了保险 希望大家在写请求消息体的时候用 接口测试工具去获取比如soapui 然后直接复制过来 String data = "<soapenv:Envelope xmlns:soapenv=" + "\"http://schemas.xmlsoap.org/soap/envelope/\" " + "xmlns:ser=\"http://server.hue.edu/\" " + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +"<soapenv:Header />" +"<soapenv:Body>" +"<ser:say >" //比如这里要调用的方法没有参数 就直接不用写就好 但是这个消息体 应该还是要的 +"</ser:say>" +"</soapenv:Body>" +"</soapenv:Envelope>";