在之前的开发过程中使用了jdk生成WebService客户端文件,然后通过文件调用接口,这种方式使用比较简单,但是我遇到了一个问题,就是传递参数传不过去,并且外部接口报500服务器内部异常。
详细情况如下:
通常的webService接口是尾缀为 ?wsdl的接口,这种接口直接在网页中打开就可以看到此接口的结构,入参,出参等内容。这种接口通过创建webService客户端文件,然后创建webService服务对象,调用服务方法。
URL url = ResourceUtils.getURL(webServiceURL);
客户端文件的Service service = new 客户端文件的Service(url);
方法返回值类型对象 point = service.调用客户端文件Service中带有@WebEndpoint注解的方法();
这种方法创建了point对象后,就可以组参数,调用接口方法了。
但是发现生产上此方法不可行,调用时接口报500异常,参数也传递不过去。
原因为带有?wsdl后缀的接口为路径地址,无此后缀的接口为路由地址。
路由地址在网页中打开是没有结构显示的,所以需要更换访问方式。
我就采用了如下方式进行webService接口访问
1.首先导入httpclient依赖
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
2.拼接需要的入参,我是通过soapUI调用后,得到的入参结构,然后进行拼接。
StringBuffer sbBuffer = new StringBuffer();
//地址
sbBuffer.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:cre=\"service地址\">");
sbBuffer.append("<soapenv:Header/>");
sbBuffer.append("<soapenv:Body>");
sbBuffer.append("<cre:接口名>");
sbBuffer.append("<入参标签开始>");
sbBuffer.append("<参数标签>"+reservoirOrder.getAuart()+"</参数标签>");
sbBuffer.append("</入参标签结束>");
sbBuffer.append("</cre:方法名>");
sbBuffer.append("</soapenv:Body>");
sbBuffer.append("</soapenv:Envelope>");
return sbBuffer.toString();
3.进行接口调用
byte[] b;//用来装入参
HttpClient httpClient = new HttpClient();//创建http客户端
PostMethod postMethod = new PostMethod(createLibOrderFromOEMToLESUrl);//将接口地址放入创建post请求
try {
postMethod.setRequestHeader("Connection", "close");//不需要请求头
//调用入参拼接方法
String soapRequestData = subLogisticsData(入参);//调用步骤2方法获得入参
b = soapRequestData.getBytes("utf-8");//将入参转换为字符串数组
InputStream is = new ByteArrayInputStream(b, 0, b.length);//将数组转换为输入流
//将输入流转换为请求的对象
RequestEntity re = new InputStreamRequestEntity(is, b.length, "application/soap+xml; charset=utf-8");
//将请求对象放入创建的post请求中
postMethod.setRequestEntity(re);
//通过http客户端进行接口调用
int statusCode = httpClient.executeMethod(postMethod);
//返回请求码为200则调用成功
if (200 == statusCode) {
//获得响应的内容字符串
String getServerData = postMethod.getResponseBodyAsString();
//进行内容解析
AddReservoirOrderDto reservoirOrderDto = this.saxLogisticsData(getServerData);
return WebResultDto.success();
}
} catch (Exception e) {
return WebResultDto.error(e.getMessage());
} finally{
//释放请求连接
postMethod.releaseConnection();
}
return WebResultDto.error("调用错误");
4.解析响应内容
//创建XML解析器对象
SAXReader saxReader = new SAXReader();
try {
//data为响应的字符串,创建输入流,进行读取
Document doc = saxReader.read(new ByteArrayInputStream(data.getBytes("UTF-8")));
//获取根节点元素下的所有子元素
Element root = doc.getRootElement();
//一层一层打开
Element body = root.element("Body");
Element response = body.element("Method");
Element output = response.element("OUTPUT");
//想要得到元素的值就使用getText()方法
output.element("元素1").getText();
output.element("元素2").getText();
}
catch (UnsupportedEncodingException | DocumentException e) {
}
解析后将响应内容返回。
用此方法就可以正常进行调用了。
这里的处理回参进行接收的方法提交后提示不安全,这里介绍一个新的方式来处理回参。可能代码略有不同,如有问题请私聊我解决。
public AddReservoirOrderDto saxLogisticsData(String data) {
AddReservoirOrderDto reservoirOrderDto = new AddReservoirOrderDto();
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
try {
DocumentBuilder builder = df.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)));
NodeList nodeList = doc.getElementsByTagName("OUTPUT").item(0).getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
if ("元素1".equals(nodeList.item(i).getNodeName())) {
reservoirOrderDto.setVbeln(nodeList.item(i).getTextContent());
}
if ("元素2".equals(nodeList.item(i).getNodeName())) {
reservoirOrderDto.setMessage(nodeList.item(i).getTextContent());
}
}
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
return reservoirOrderDto;
}