Java调用WebService方法总结(2)--JAX-WS调用WebService
用JAX-WS(Java API for XML Web Services)调用WebService不需要引入其他框架,都是JDK自带的;文中所使用到的软件版本:Java 1.8.0_191。
1、准备
参考Java调用WebService方法总结(1)--准备工作
2、调用
2.1、Dispatch方式
Dispatch又有Payload方式和Message两种方式。
2.1.1、Payload方式
在payload方式中,只需传入SOAP消息中的body部分。
/** * dispatch Payload方式调用WebService * @param portName 端口名称 * @param param 参数 */ public static void dispatchPayload(String portName, String param) { try { StringBuffer source = new StringBuffer(); source.append("<web:toTraditionalChinese xmlns:web=\"" + targetNamespace + "\">"); source.append("<web:sText>").append(param).append("</web:sText>"); source.append("</web:toTraditionalChinese>"); StreamSource xmlSource = new StreamSource(new StringReader(source.toString())); URL wsdlURL = new URL(url); QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService"); Service service = Service.create(wsdlURL, serviceQName); QName portQName = new QName(targetNamespace, portName); Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD); //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值 Map<String, Object> requestContext = dispatch.getRequestContext(); requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE); requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese"); Source orderSource = dispatch.invoke(xmlSource); StreamResult result = new StreamResult(new ByteArrayOutputStream()); Transformer trans = TransformerFactory.newInstance().newTransformer(); trans.transform(orderSource, result); ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream(); String responseContent = new String(baos.toByteArray()); System.out.println(responseContent); Reader file = new StringReader(responseContent); SAXReader reader = new SAXReader(); Document dc = reader.read(file); Element root = dc.getRootElement(); String r = root.elementText("toTraditionalChineseResult").trim(); System.out.println(r); } catch (Exception e) { e.printStackTrace(); } }
2.1.2、Message方式
在Message方式中,需传入整个Soap消息。
/** * dispatch Payload方式调用WebService * @param soapNamespace soap消息整个消息体的命名空间,Soap1.1和Soap1.2不一样 * @param portName 端口名称 * @param param 参数 */ public static void dispatchMessage(String soapNamespace, String portName, String param) { try { StringBuffer source = new StringBuffer(); source.append("<soapenv:Envelope xmlns:soapenv=\"" + soapNamespace + "\" xmlns:web=\"" + targetNamespace + "\">"); source.append("<soapenv:Header/>"); source.append("<soapenv:Body>"); source.append("<web:toTraditionalChinese>"); source.append("<web:sText>").append(param).append("</web:sText>"); source.append("</web:toTraditionalChinese>"); source.append("</soapenv:Body>"); source.append("</soapenv:Envelope>"); StreamSource xmlSource = new StreamSource(new StringReader(source.toString())); URL wsdlURL = new URL(url); QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService"); Service service = Service.create(wsdlURL, serviceQName); QName portQName = new QName(targetNamespace, portName); Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE); //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值 Map<String, Object> requestContext = dispatch.getRequestContext(); requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE); requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese"); Source orderSource = dispatch.invoke(xmlSource); StreamResult result = new StreamResult(new ByteArrayOutputStream()); Transformer trans = TransformerFactory.newInstance().newTransformer(); trans.transform(orderSource, result); ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream(); String responseContent = new String(baos.toByteArray()); System.out.println(responseContent); Reader file = new StringReader(responseContent); SAXReader reader = new SAXReader(); Document dc = reader.read(file); //节点名称为toTraditionalChineseResult 命名空间为http://webxml.com.cn/ String r = dc.selectSingleNode("//*[local-name()='toTraditionalChineseResult' and namespace-uri()='http://webxml.com.cn/']").getText().trim(); System.out.println(r); } catch (Exception e) { e.printStackTrace(); } }
2.1.3、完整代码
代码中的设置的信息都可以在准备工作中查询到,或WSDL中或Soap消息中,这里就不一一解释了。完整代码如下:
package com.abc.ws; import java.io.ByteArrayOutputStream; import java.io.Reader; import java.io.StringReader; import java.net.URL; import java.util.Map; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.BindingProvider; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * JAX-WS Dispatch方式调用WebService样例 * @author wuyy * */ public class JaxWsDispatch { private static String url = "http://www.webxml.com.cn/WebServices/TraditionalSimplifiedWebService.asmx?wsdl"; private static String targetNamespace = "http://webxml.com.cn/"; /** * dispatch Payload方式调用WebService * @param portName 端口名称 * @param param 参数 */ public static void dispatchPayload(String portName, String param) { try { StringBuffer source = new StringBuffer(); source.append("<web:toTraditionalChinese xmlns:web=\"" + targetNamespace + "\">"); source.append("<web:sText>").append(param).append("</web:sText>"); source.append("</web:toTraditionalChinese>"); StreamSource xmlSource = new StreamSource(new StringReader(source.toString())); URL wsdlURL = new URL(url); QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService"); Service service = Service.create(wsdlURL, serviceQName); QName portQName = new QName(targetNamespace, portName); Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD); //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值 Map<String, Object> requestContext = dispatch.getRequestContext(); requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE); requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese"); Source orderSource = dispatch.invoke(xmlSource); StreamResult result = new StreamResult(new ByteArrayOutputStream()); Transformer trans = TransformerFactory.newInstance().newTransformer(); trans.transform(orderSource, result); ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream(); String responseContent = new String(baos.toByteArray()); System.out.println(responseContent); Reader file = new StringReader(responseContent); SAXReader reader = new SAXReader(); Document dc = reader.read(file); Element root = dc.getRootElement(); String r = root.elementText("toTraditionalChineseResult").trim(); System.out.println(r); } catch (Exception e) { e.printStackTrace(); } } /** * dispatch Payload方式调用WebService * @param soapNamespace soap消息整个消息体的命名空间,Soap1.1和Soap1.2不一样 * @param portName 端口名称 * @param param 参数 */ public static void dispatchMessage(String soapNamespace, String portName, String param) { try { StringBuffer source = new StringBuffer(); source.append("<soapenv:Envelope xmlns:soapenv=\"" + soapNamespace + "\" xmlns:web=\"" + targetNamespace + "\">"); source.append("<soapenv:Header/>"); source.append("<soapenv:Body>"); source.append("<web:toTraditionalChinese>"); source.append("<web:sText>").append(param).append("</web:sText>"); source.append("</web:toTraditionalChinese>"); source.append("</soapenv:Body>"); source.append("</soapenv:Envelope>"); StreamSource xmlSource = new StreamSource(new StringReader(source.toString())); URL wsdlURL = new URL(url); QName serviceQName = new QName(targetNamespace, "TraditionalSimplifiedWebService"); Service service = Service.create(wsdlURL, serviceQName); QName portQName = new QName(targetNamespace, portName); Dispatch<Source> dispatch = service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE); //.NET的服务端Soap1.1需要,不加会报错误:服务器未能识别 HTTP 头 SOAPAction 的值 Map<String, Object> requestContext = dispatch.getRequestContext(); requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE); requestContext.put(BindingProvider.SOAPACTION_URI_PROPERTY, "http://webxml.com.cn/toTraditionalChinese"); Source orderSource = dispatch.invoke(xmlSource); StreamResult result = new StreamResult(new ByteArrayOutputStream()); Transformer trans = TransformerFactory.newInstance().newTransformer(); trans.transform(orderSource, result); ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream(); String responseContent = new String(baos.toByteArray()); System.out.println(responseContent); Reader file = new StringReader(responseContent); SAXReader reader = new SAXReader(); Document dc = reader.read(file); //节点名称为toTraditionalChineseResult 命名空间为http://webxml.com.cn/ String r = dc.selectSingleNode("//*[local-name()='toTraditionalChineseResult' and namespace-uri()='http://webxml.com.cn/']").getText().trim(); System.out.println(r); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { //Soap1.1对应的portName为TraditionalSimplifiedWebServiceSoap,Soap1.2对应的portName为TraditionalSimplifiedWebServiceSoap12 dispatchPayload("TraditionalSimplifiedWebServiceSoap", "小学"); dispatchPayload("TraditionalSimplifiedWebServiceSoap12", "大学"); //Soap1.1对应的soapNamespace为http://schemas.xmlsoap.org/soap/envelope/,Soap1.1对应的soapNamespace为http://www.w3.org/2003/05/soap-envelope dispatchMessage("http://schemas.xmlsoap.org/soap/envelope/", "TraditionalSimplifiedWebServiceSoap", "小学"); dispatchMessage("http://www.w3.org/2003/05/soap-envelope", "TraditionalSimplifiedWebServiceSoap12", "大学"); } }
2.2、Proxy方式
该方式代码很简洁,需把接口类ITestService拷贝到客户端工程里。调用本地服务如下:
package com.abc.ws; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; import com.abc.ws.ITestService; /** * JAX-WS Proxy调用 ,需把接口类拷贝到客户端 * */ public class JaxWsProxy { private static String url = "http://10.49.196.10:9006/myservice/TestService?wsdl"; private static String targetNamespace = "http://ws.abc.com/"; public static void proxy(String param) { try { QName qname = new QName(targetNamespace, "TestService"); Service service = Service.create(new URL(url), qname); ITestService testService = service.getPort(ITestService.class); System.out.println(testService.hello(param)); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { proxy("大学"); } }
2.3、RPC方式
RPC方式已不被推荐使用了,但JAX-WS依然支持。改方式与Proxy有点相似,也需把接口类ITestService拷贝到客户端工程里面;与Proxy方式不同的是:接口类还需继承java.rmi.Remote接口,使用的类是javax.xml.rpc包下。
package com.abc.ws; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; import com.abc.ws.ITestService; /** * JAX-WS RPC调用 ,需把接口类拷贝到客户端,接口类需继承java.rmi.Remote接口 * */ public class JaxWsRpc { private static String url = "http://10.49.196.10:9006/myservice/TestService?wsdl"; private static String targetNamespace = "http://ws.abc.com/"; public static void rpc(String param) { try { ServiceFactory serviceFactory = ServiceFactory.newInstance(); Service service = serviceFactory.createService(new URL(url), new QName(targetNamespace, "TestService")); ITestService testService = (ITestService) service.getPort(ITestService.class); String result = testService.hello(param); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { rpc("大学"); } }
3、JDK9+ 版本处理
JDK9 及更高版本把 JAX-WS 相关包移除了,如需使用可添加如下包:
<dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.3.7</version> </dependency>