一、业务场景
通过调三方系统查询接口拉取数据,生成本方系统单据。
二、实现分析
三方资管系统提供的查询接口为WebService接口,与http接口不同的是,WebService使用XML来封装数据,所以通过将接口返回的[xml]格式字符串转为Document对象和Json对象两种方式,来解析数据。
三、实现过程
1. 查看调用方法
接口地址:http://ip:port/FDLKF_OUTER/webservice/TxServiceGateway?wsdl
根据接口的wsdl文档可以知道调用的接口方法:send
2. 查看调用格式
- 通过SoapUI工具解析,可查看调用接口参数的SOAP格式
- 封装xml请求参数
public static String getXML() {
//公共请求参数
String code = "9002";
long batchNo = System.currentTimeMillis();
String nodeId = "client.001";
String channelId = "RJ_NC";
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmssSSS");
String txDateTime=sdf.format(d);
SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd");
Calendar nowTime = Calendar.getInstance();
String queryStartDate = sdf1.format(nowTime.getTime());
String soapXML = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservice.fdlk.nstc.com\">\r\n" +
" <soapenv:Header/>\r\n" +
" <soapenv:Body>\r\n" +
" <web:send>\r\n" +
" <!--Optional:-->\r\n" +
" <message>\r\n" +
" <![CDATA[\r\n" +
" <fdlk>\r\n" +
" <code>"+ code +"</code>\r\n" +
" <batchNo>"+ batchNo +"</batchNo>\r\n" +
" <nodeId>"+ nodeId +"</nodeId>\r\n" +
" <ackCode></ackCode>\r\n" +
" <channelId>"+ channelId +"</channelId>\r\n" +
" <clientId></clientId>\r\n" +
" <clientName></clientName>\r\n" +
" <txDateTime>"+ txDateTime +"</txDateTime>\r\n" +
" <sendNodeId></sendNodeId>\r\n" +
" <data>\r\n" +
" <item>\r\n" +
" <chnal>"+ channelId +"</chnal>\r\n" +
" <start_date>"+ queryStartDate +"</start_date>\r\n" +
" <end_date>"+ queryStartDate +"</end_date>\r\n" +
" <clt_name></clt_name>\r\n" +
" <acct_no></acct_no>\r\n" +
" </item>\r\n" +
" </data>\r\n" +
" </fdlk>\r\n" +
" ]]>\r\n" +
" </message>\r\n" +
" </web:send>\r\n" +
" </soapenv:Body>\r\n" +
"</soapenv:Envelope>";
return soapXML;
}
3. 调用接口
- 使用post直接请求,以下调用接口工具类
package nc.data.json.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import org.apache.log4j.Logger;
import org.json.JSONObject;
import org.json.XML;
/**
* @version 1.0.0
* @ClassName SoapUtil.java
* @Description webservice调用工具类
* @createTime 2022/6/19 14:37
*/
public class SoapUtil {
/**
* 发送http post调用webservice
*
* @param strUrl
* @param body
* @return
* @throws IOException
*/
public static String soapPost(String strUrl, String requestBody) throws Exception {
HttpURLConnection httpURLConnection = null;
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
//1.创建服务地址,不是WSDL地址
try {
URL url = new URL(strUrl);
//2.打开一个通向服务地址的连接
URLConnection conn = url.openConnection();
httpURLConnection = (HttpURLConnection) conn;
//3.设置参数
// 设置连接超时时间和读取超时时间
httpURLConnection.setConnectTimeout(60 * 1000);
httpURLConnection.setReadTimeout(60 * 1000);
httpURLConnection.setRequestMethod("POST"); // 设置请求方式
httpURLConnection.setRequestProperty("content-type", "text/xml;charset=UTF-8");
// 发送POST请求必须设置如下两行
httpURLConnection.setDoOutput(true); // 是否有出参
httpURLConnection.setDoInput(true); // 是否有入参
// 4.通过流的方式将请求体发送出去:
OutputStream out = httpURLConnection.getOutputStream();
out.write(requestBody.getBytes());
out.close();
// 5.服务端返回正常:
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == 200) {// 服务端返回正常
InputStream is = httpURLConnection.getInputStream();
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String temp = null;
while(null != (temp = br.readLine())){
sb.append(temp);
}
is.close();
}else {
throw new Exception("调用查询接口失败:服务器端返回HTTP code " + responseCode );
}
return sb.toString(); //数据格式为xml字符串
} catch (Exception e) {
throw new Exception(e.getMessage());
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
if (br != null) {
br.close();
}
}
}
}
说明:读取响应数据的字节流InputStream
原本是按字节数组转为字符串方式,但在和三方系统联调测试过程中,出现了个别中文乱码的情况,后来将字节流转为字符流InputStreamReader
的方式成功解决。
字节流个别中文乱码
InputStream is = httpURLConnection.getInputStream();
byte[] b = new byte[1024];
StringBuffer sb = new StringBuffer();
int len = 0;
while ((len = is.read(b)) != -1) {
String str = new String(b, 0, len, "UTF-8");
sb.append(str);
}
字节流转为字符流成功解决乱码
InputStream is = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String temp = null;
while(null != (temp = br.readLine())){
sb.append(temp);
}
- 返回的xml字符串response数据如下
4. 解析xml数据
解析xml数据方式有两种,将xml字符串转为Document对象和Json对象进行数据处理
- 将xml字符串转为Document对象
public static List<Element> convertXmlIntoDocumentObject(String response) {
List<Element> elements = new ArrayList();
try {
// 将xml格式的字符串解析为Document对象
Document document = DocumentHelper.parseText(response);
// 获取文档根节点
Element root = document.getRootElement();
// 输出根标签的名字
System.out.println(root.getName());
// 获取根节点下面的所有子节点(不包过子节点的子节点)
List<Element> element = root.elements();
Element Body = element.get(0);
Element sendResponse = (Element)Body.elements().get(0);
Element returnMessage = (Element)sendResponse.elements().get(0);
//xml字符串
String xml = returnMessage.getText();
SAXReader reader = new SAXReader();
Document xmlDocument = reader.read(new StringReader(xml));
Element fdlk = xmlDocument.getRootElement();
if(fdlk.elementText("resultCode").equals("000000")){
Element data = fdlk.element("data").element("data");
elements = data.elements("detaillist");
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return elements;
}
- 将xml字符串转为Json对象
/**
* 传字符串格式的xml 将xml格式<a/>装换成<a></a> 再将xml装换成属性没有带"@"的JSONObject格
* */
public static JSONObject convertXmlIntoJSONObject(String response) {
try {
//使用hutool工具类,取出在xml结点中的最终数据
JSONObject json = XML.toJSONObject(response);
//xml字符串
String xml = json.getJSONObject("soap:Envelope").getJSONObject("soap:Body").getJSONObject("ns2:sendResponse").getString("returnMessage");
Document xmlDocument = DocumentHelper.parseText(xml);
OutputFormat format = new OutputFormat();
format.setEncoding("UTF-8");
format.setExpandEmptyElements(true);
StringWriter out = new StringWriter();
XMLWriter writer = new XMLWriter(out, format);
try {
writer.write(xmlDocument);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
// out.toString() 此结果为xml的<a></a>格式
JSONObject jsonObject = XML.toJSONObject(out.toString());
} catch (DocumentException e1) {
e1.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
注意:用XML.toJSONObject()转为JSON数据时,当detaillist只有一条数据时,会转换为一个JSON对象;当detaillist大于一条数据时,会转为一个JSON数组
/**
* 处理请求返回数据
* @param response
* @return
* @throws BusinessException
*/
private String handleData(JSONObject jsonObject) throws Exception {
String errmsg = "";
JSONObject fdlk = jsonObject.getJSONObject("fdlk");
String resultCode = fdlk.getString("resultCode");
if(resultCode.equals("0")){
JSONObject data = fdlk.getJSONObject("data").getJSONObject("data");
if(data.getInt("count") > 0){
if(data.getInt("count") == 1){
JSONArray jsonArray = new JSONArray();
//当detaillist只有一条数据时,为一个JSON对象
jsonArray.put(data.getJSONObject("detaillist"));
errmsg = addBill(jsonArray);
}else{
//当detaillist大于一条数据时,为一个JSON数组
JSONArray jsonArray = data.getJSONArray("detaillist");
errmsg = addBill(jsonArray);
}
}
}
return errmsg;
}