WebService使用HTTP协议发送请求,
使用XML格式封装数据,本文讲述WebService接口开发与调用。
使用JAVA原生WS注解完成WebService接口服务端开发
创建WS接口与实现类
//接口@WebService(targetNamespace = "http://cxf.test", name = "WSTest")@XmlSeeAlso({ObjectFactory.class})@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)public interface WSTest { @WebMethod(action = "http://cxf.test/ws") public WSResponse test( @WebParam(name = "WSHeader", targetNamespace = "http://cxf.test",header = true) WSHeader WSHeader, @WebParam(name = "WSRequest", targetNamespace = "http://cxf.test") WSRequest WSRequest );}//实现类@WebService( serviceName = "WSTest", portName = "WSTest", targetNamespace = "http://cxf.test", endpointInterface = "cxf.server.WSTest")public class WSTestImpl implements WSTest{ @Override public WSResponse test(WSHeader WSHeader, WSRequest WSRequest) { Logger.getLogger(this.getClass().getName()).info("请求已接收"); WSResponse response = new WSResponse(); response.setTestResponseBody(WSHeader.getTestHeader()+"==>"+WSRequest.getTestRequestBody()); return response; }}
创建命名空间规范
@XmlRegistrypublic class ObjectFactory { private final static QName _WSRequest_QNAME = new QName("http://cxf.test", "WSRequest"); private final static QName _WSResponse_QNAME = new QName("http://cxf.test", "WSResponse"); private final static QName _WSHeader_QNAME = new QName("http://cxf.test", "WSHeader"); public ObjectFactory() { } public WSRequest createWSRequest(){ return new WSRequest(); } public WSResponse createWSResponse(){ return new WSResponse(); } public WSHeader createWSHeader(){ return new WSHeader(); } @XmlElementDecl(namespace = "http://cxf.test", name = "WSRequest") public JAXBElementcreateWSRequest(WSRequest value) { return new JAXBElement(_WSRequest_QNAME, WSRequest .class, null, value); } @XmlElementDecl(namespace = "http://cxf.test", name = "WSResponse") public JAXBElementcreateWSResponse(WSResponse value) { return new JAXBElement(_WSResponse_QNAME, WSResponse .class, null, value); } @XmlElementDecl(namespace = "http://cxf.test", name = "WSHeader") public JAXBElementcreateWSHeader(WSHeader value) { return new JAXBElement(_WSHeader_QNAME, WSHeader.class, null, value); }}
创建请求头类、请求体类、响应类,与接口启动类
public class WSServer { public static void main(String[] args) { Object implementor = new WSTestImpl(); String address = "http://127.0.0.1:55555/cxf/test"; Endpoint.publish(address, implementor); Logger.getLogger(Thread.currentThread().getName()).info("启动成功"); }}
使用apache的CXF组件生成客户端代码,进行调用
//CXF生成代码的命令wsdl2java -encoding utf8 -p cxf.client -d C:\work\STS\cxf\src -client http://127.0.0.1:55555/cxf/test?wsdl#-encoding utf8:设置文件编码#-p cxf.client:设置包名#-d C:\work\STS\cxf\src:设置生成路径#-client:生成客户端代码//客户端代码如下:public final class WSTest_WSTest_Client { private static final QName SERVICE_NAME = new QName("http://cxf.test", "WSTest"); private WSTest_WSTest_Client() { } public static void main(String args[]) throws java.lang.Exception { URL wsdlURL = WSTest_Service.WSDL_LOCATION; if (args.length > 0 && args[0] != null && !"".equals(args[0])) { File wsdlFile = new File(args[0]); try { if (wsdlFile.exists()) { wsdlURL = wsdlFile.toURI().toURL(); } else { wsdlURL = new URL(args[0]); } } catch (MalformedURLException e) { e.printStackTrace(); } } WSTest_Service ss = new WSTest_Service(wsdlURL, SERVICE_NAME); WSTest port = ss.getWSTest(); { System.out.println("Invoking test..."); cxf.client.WSHeader _test_wsHeader = null; cxf.client.WSRequest _test_wsRequest = null; cxf.client.WSResponse _test__return = port.test(_test_wsHeader, _test_wsRequest); System.out.println("test.result=" + _test__return); } System.exit(0); }}
使用SoapUI+postman生成OkHttp调用代码,并通过JAVA对象构建请求报文与解析响应报文
很多时候由于服务端并没有按照SOAP协议开发,导致CXF生成的客户端代码并不能实现调用,因此需要使用SoapUI工具根据wsdl文件生成调用示例,然后使用postman(下文以快递侠命名)工具把SoapUI的调用示例转换为快递侠的调用示例,最后生成OkHttp调用代码。一、将WSDL导入 SoapUI 二、转换为快递侠调用示例 三、生成OkHttp调用代码四、实际代码
//调用示例public class Test { public static void main(String[] args) { //1、根据请求报文的格式与命名空间构建请求报文的类,并生成请求报文 String json = ""; try (StringWriter writer = new StringWriter()) { JAXBContext context = JAXBContext.newInstance(RequestEnvelope.class); Marshaller marshal = context.createMarshaller(); marshal.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshal.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); marshal.setProperty(Marshaller.JAXB_FRAGMENT, false); marshal.setProperty("jaxb.encoding", "utf-8"); RequestEnvelope root = new RequestEnvelope(); RequestBody body = new RequestBody(); WSRequest request = new WSRequest(); request.setTestRequestBody("啊"); body.setWSRequest(request); RequestHeader header = new RequestHeader(); WSHeader wsHeader = new WSHeader(); wsHeader.setTestHeader("我是java"); header.setWSHeader(wsHeader); root.setHeader(header); root.setBody(body); marshal.marshal(root,writer); json = new String(writer.getBuffer()); } catch (Exception e) { e.printStackTrace(); } System.out.println(json); //2、使用快递侠生成的OkHttp代码调用WS接口 OkHttpClient client = new OkHttpClient().newBuilder().build(); MediaType mediaType = MediaType.parse("text/xml"); okhttp3.RequestBody body = okhttp3.RequestBody.create(mediaType,json); Request request = new Request.Builder() .url("http://127.0.0.1:55555/cxf/test") .method("POST", body) .addHeader("Content-Type", "text/xml") .build(); //3、拿到返回值后,继续根据响应报文的格式与命名空间,解析响应报文的类,拿到响应对象 try (Response response = client.newCall(request).execute()) { String xml = response.body().string(); SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); spf.setNamespaceAware(true); JAXBContext context = JAXBContext.newInstance(ResponseEnvelope.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(new StringReader(xml))); ResponseEnvelope root = (ResponseEnvelope) unmarshaller.unmarshal(xmlSource); System.out.println(root.getBody().getTestResponse().getTestResponseBody()); } catch (Exception e) { e.printStackTrace(); } }}//OkHttp的maven依赖 com.squareup.okhttp3 okhttp 3.11.0
其他文章推荐:
Centos 7 安装指定版本的docker(如19.03.9)
容器级别redis问题探讨
巧用VPN打通容器云网络
本文中用到的文件,百度网盘下载地址如下:
链接:https://pan.baidu.com/s/1VtBlq7Pge4QB50gi7Zs0Ig
提取码:s7fd
关注此微信公众号,获得每日程序员干货推送