网上查找资料总结有以下实现方式
1)使用命令生成接口和实体类,如wsimport -p . -keep http://localhost:8080/hello?wsdl,直接调取接口使用,但是生成了一大堆文件
2)xfire,后续版本cxf,个人建议使用,兼容大多数
3)axis,后续版本axis2,调用webservice感觉兼容性差,但是用来发布webservice感觉很方便,axis2本身就是一个web服务,只需要把写好的.class方法文件往服务路径里面一扔一个webservice就对外发布了
4)直接使用http请求,get和post方法都可以,就是自己封装成envelop的xml格式参数,get方法需要得到输入流往里面写入参数,post方法可以直接将xml参数作为实体传参,我使用post方法实现。
下面是我的做法
1)先考虑使用cxf,因为cxf调用起来真心的简单。
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.1.9</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>3.1.9</version> </dependency>下面是调用demo,如果对同一个webservice服务多次调用,可以将client静态缓存。
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient("http://localhost:9003/soap?wsdl"); Object[] o=new Object[]{"arg0","arg1"};//入参按照方法的顺序填充 try { Object[] result = client.invoke("getUser",o);//getUser是方法名,client.invoke("getUser","liu","fang"); //输出调用结果 System.out.println(result[0].getClass()); System.out.println(result[0].toString()); System.out.println(JSONObject.fromObject(result[0]).toString()); } catch (Exception e) { e.printStackTrace(); }
2)cxf调不通的,一般是C#写的webservice,1)入参使用了ref这种结构 2)出参解析的时候多了一个实体类的描述,在这种情况我直接用http请求自己解析xml实现。
网上有很多demo
用org.apache.httpcomponents httpcore的HttpWebRequest实现http://www.cnblogs.com/hfliyi/archive/2012/09/16/2687843.html
用HttpURLConnection实现 http://blog.csdn.net/bjxyj/article/details/46725899 http://blog.csdn.net/bjxyj
我现在使用httpClient的CloseableHttpClient实现,没有启用连接池
public static String doHttpPost(String apiUrl, String content,String contentType) throws Exception{ CloseableHttpClient httpClient = HttpClients.createDefault(); String httpStr = null; HttpPost httpPost = new HttpPost(apiUrl); CloseableHttpResponse response = null; try { StringEntity stringEntity = new StringEntity(content, "UTF-8"); stringEntity.setContentEncoding("UTF-8"); stringEntity.setContentType(contentType); httpPost.setEntity(stringEntity); response = httpClient.execute(httpPost); httpStr = EntityUtils.toString(response.getEntity(), "UTF-8"); } catch (Exception e) { throw e; } finally { if (response != null) { try { EntityUtils.consume(response.getEntity()); } catch (IOException e) { e.printStackTrace(); } } } httpClient.close(); return httpStr; }
public static String doPost(String webserviceURL,Object[] objects) throws Exception { return doHttpPost(webserviceURL,buildXML(objects),"text/xml;charset=utf-8"); } public static String buildXML(Object[] objects){ StringBuilder sb = new StringBuilder("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tns=\"http://tempuri.org/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");注意调通的关键是xml参数,你可以使用soapUI工具进行调试sb.append("<soap:Header/>"); sb.append("<soap:Body>"); sb.append("<tns:getUser>");//我实际调用时方法名用objects[0] sb.append("<arg0>liu</arg0>");//我实际调用时参数1使用objects[1] sb.append("<arg1>fang</arg1>");//我实际调用时参数2使用objects[2] sb.append("</tns:getUser>");//我实际调用时使用objects[0] sb.append("</soap:Body>"); sb.append("</soap:Envelope>"); return sb.toString();}
soap是引用信封envelope,参数值固定,soap可以修改成其它名字如soapenv,如果改成了soapenv后面的标签中soap也需要修改
tns后面接的是命名空间,直接访问?wsdl路径就可以看到,没有修改的话默认就是http://tempuri.org/,tns也可以改成其它的名字,如常见的tem,相应的后面的方法和参数标签中也需要修改。关于入参,一般参数和方法的写法一致也要加上tns:的前缀,但在我的demo中参数必须是arg0,arg1,arg2这种写法才能取到值。
一般webservice要写成这样,如<tns:getUser><tns:firstname>liufang</tns:firstname><tns:lastname>fang</tns:lastname></tns:getUser>
xsd在本例中可以不用添加
我测试时发布webservice采用最简单的方法
public String getUser(String firstname,String lastname){ return firstname+" "+lastname; } public static void main(String[] args) { javax.xml.ws.Endpoint.publish("http://localhost:9003/soap", new NativeMethod()); System.out.println("werbservice publish success"); }