parent
f781bc633a
commit
2892048cf4
@ -0,0 +1,288 @@ |
|||||||
|
package com.sinosoft.lis.wsclient; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.net.URI; |
||||||
|
import java.net.http.HttpClient; |
||||||
|
import java.net.http.HttpRequest; |
||||||
|
import java.net.http.HttpResponse; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.text.SimpleDateFormat; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* 询价计划信息服务 |
||||||
|
* 调用外部WebService接口查询AskPlan信息 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class AskPlanInfoService { |
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AskPlanInfoService.class); |
||||||
|
|
||||||
|
// 接口地址
|
||||||
|
private static final String WS_URL = "http://112.124.61.57:9998/ws/dealDataWebService"; |
||||||
|
|
||||||
|
// 业务参数
|
||||||
|
private static final String SYS_CODE = "GCS2ASK20191123000001"; |
||||||
|
private static final String FUNC_FLAG = "GRFQ000002"; |
||||||
|
|
||||||
|
// SOAP命名空间(根据实际WSDL调整)
|
||||||
|
private static final String SOAP_NAMESPACE = "http://webservice.sinosoft.com.cn"; |
||||||
|
|
||||||
|
/** |
||||||
|
* 查询询价计划信息 |
||||||
|
* |
||||||
|
* @param askNo 询价单号(如:17751055) |
||||||
|
* @return 响应XML字符串,失败返回null |
||||||
|
*/ |
||||||
|
public String queryAskPlanInfo(String askNo, String batchNo) { |
||||||
|
// 参数校验
|
||||||
|
if (askNo == null || askNo.trim().isEmpty()) { |
||||||
|
log.error("查询AskPlanInfo失败:askNo参数为空"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
if (batchNo == null || batchNo.trim().isEmpty()) { |
||||||
|
log.error("查询AskPlanInfo失败:batchNo参数为空"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
log.info("开始查询AskPlanInfo,询价单号: {},批次号: {}", askNo,batchNo); |
||||||
|
|
||||||
|
try { |
||||||
|
// 1. 构建业务XML(CDATA中的内容)
|
||||||
|
String businessXml = buildBusinessXml(askNo, batchNo); |
||||||
|
log.debug("业务XML:\n{}", businessXml); |
||||||
|
|
||||||
|
// 2. 构建SOAP请求(业务XML放在CDATA中)
|
||||||
|
String soapRequest = buildSoapRequest(businessXml); |
||||||
|
log.info("SOAP请求:\n{}", soapRequest); |
||||||
|
|
||||||
|
// 3. 发送SOAP请求
|
||||||
|
String soapResponse = sendSoapRequest(soapRequest); |
||||||
|
if (soapResponse == null) { |
||||||
|
log.error("SOAP请求返回空响应"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
log.info("SOAP响应:\n{}", soapResponse); |
||||||
|
|
||||||
|
// 4. 从SOAP响应中提取业务响应
|
||||||
|
String businessResponse = extractBusinessResponse(soapResponse); |
||||||
|
if (businessResponse == null) { |
||||||
|
log.error("提取业务响应失败"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
log.info("业务响应:\n{}", businessResponse); |
||||||
|
|
||||||
|
// 5. 检查业务返回码
|
||||||
|
String returnCode = extractXmlValue(businessResponse, "ReturnCode"); |
||||||
|
if ("000000".equals(returnCode)) { |
||||||
|
log.info("查询成功,询价单号: {}", askNo); |
||||||
|
} else { |
||||||
|
String message = extractXmlValue(businessResponse, "Message"); |
||||||
|
log.warn("查询返回非成功状态,返回码: {}, 消息: {}", returnCode, message); |
||||||
|
} |
||||||
|
|
||||||
|
return businessResponse; |
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
log.error("查询AskPlanInfo异常,询价单号: {}", askNo, e); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 构建业务XML(将被放在CDATA中) |
||||||
|
*/ |
||||||
|
private String buildBusinessXml(String askNo, String batchNo) { |
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); |
||||||
|
SimpleDateFormat timeFormat = new SimpleDateFormat("HHmmss"); |
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
StringBuilder xml = new StringBuilder(); |
||||||
|
xml.append("<?xml version=\"1.0\" encoding=\"GBK\"?>\n"); |
||||||
|
xml.append("<TX>\n"); |
||||||
|
xml.append(" <ENTITY>\n"); |
||||||
|
xml.append(" <TRANSHEAD>\n"); |
||||||
|
xml.append(" <SysCode>").append(SYS_CODE).append("</SysCode>\n"); |
||||||
|
xml.append(" <FuncFlag>").append(FUNC_FLAG).append("</FuncFlag>\n"); |
||||||
|
xml.append(" <TransDate>").append(dateFormat.format(now)).append("</TransDate>\n"); |
||||||
|
xml.append(" <TransTime>").append(timeFormat.format(now)).append("</TransTime>\n"); |
||||||
|
xml.append(" </TRANSHEAD>\n"); |
||||||
|
xml.append(" <TRANSBODY>\n"); |
||||||
|
xml.append(" <AskNo>").append(escapeXml(askNo)).append("</AskNo>\n"); |
||||||
|
xml.append(" <AskBatchNo>").append(escapeXml(batchNo)).append("</AskBatchNo>\n"); |
||||||
|
// xml.append(" <PolApplyDate>").append(dateFormat.format(now)).append("</PolApplyDate>\n"); // 改成 yyyyMMdd
|
||||||
|
xml.append(" <PolApplyDate></PolApplyDate>\n"); // 改成 yyyyMMdd
|
||||||
|
xml.append(" </TRANSBODY>\n"); |
||||||
|
xml.append(" </ENTITY>\n"); |
||||||
|
xml.append("</TX>"); |
||||||
|
|
||||||
|
return xml.toString(); |
||||||
|
} |
||||||
|
/** |
||||||
|
* 构建SOAP请求(CDATA包装业务XML) |
||||||
|
*/ |
||||||
|
private String buildSoapRequest(String businessXml) { |
||||||
|
StringBuilder soap = new StringBuilder(); |
||||||
|
soap.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
||||||
|
soap.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"); |
||||||
|
soap.append(" xmlns:web=\"").append(SOAP_NAMESPACE).append("\">\n"); |
||||||
|
soap.append(" <soapenv:Header/>\n"); |
||||||
|
soap.append(" <soapenv:Body>\n"); |
||||||
|
soap.append(" <web:queryAskPlanInfo>\n"); |
||||||
|
soap.append(" <arg0><![CDATA[").append(businessXml).append("]]></arg0>\n"); |
||||||
|
soap.append(" </web:queryAskPlanInfo>\n"); |
||||||
|
soap.append(" </soapenv:Body>\n"); |
||||||
|
soap.append("</soapenv:Envelope>"); |
||||||
|
|
||||||
|
return soap.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 发送SOAP请求 |
||||||
|
*/ |
||||||
|
private String sendSoapRequest(String soapRequest) { |
||||||
|
try { |
||||||
|
// 创建HttpClient
|
||||||
|
HttpClient client = HttpClient.newBuilder() |
||||||
|
.connectTimeout(java.time.Duration.ofSeconds(30)) |
||||||
|
.build(); |
||||||
|
|
||||||
|
// 构建HttpRequest
|
||||||
|
HttpRequest request = HttpRequest.newBuilder() |
||||||
|
.uri(URI.create(WS_URL)) |
||||||
|
.header("Content-Type", "text/xml; charset=UTF-8") |
||||||
|
.header("SOAPAction", "") |
||||||
|
.POST(HttpRequest.BodyPublishers.ofString(soapRequest, StandardCharsets.UTF_8)) |
||||||
|
.build(); |
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpResponse<String> response = client.send(request, |
||||||
|
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); |
||||||
|
|
||||||
|
int statusCode = response.statusCode(); |
||||||
|
log.info("HTTP响应状态码: {}", statusCode); |
||||||
|
|
||||||
|
if (statusCode != 200) { |
||||||
|
log.error("HTTP请求失败,状态码: {}, 响应: {}", statusCode, response.body()); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
String responseBody = response.body(); |
||||||
|
|
||||||
|
// 检查是否有SOAP错误
|
||||||
|
if (responseBody.contains("<soap:Fault>") || responseBody.contains("<soapenv:Fault>")) { |
||||||
|
log.error("SOAP调用失败: {}", responseBody); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return responseBody; |
||||||
|
|
||||||
|
} catch (IOException | InterruptedException e) { |
||||||
|
log.error("发送SOAP请求异常", e); |
||||||
|
Thread.currentThread().interrupt(); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String extractBusinessResponse(String soapResponse) { |
||||||
|
if (soapResponse == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
// 查找 <return> 标签
|
||||||
|
String startTag = "<return>"; |
||||||
|
String endTag = "</return>"; |
||||||
|
|
||||||
|
int startIdx = soapResponse.indexOf(startTag); |
||||||
|
if (startIdx == -1) { |
||||||
|
log.warn("未找到<return>标签"); |
||||||
|
return soapResponse; |
||||||
|
} |
||||||
|
|
||||||
|
int endIdx = soapResponse.indexOf(endTag, startIdx); |
||||||
|
if (endIdx == -1) { |
||||||
|
log.warn("未找到</return>标签"); |
||||||
|
return soapResponse; |
||||||
|
} |
||||||
|
|
||||||
|
// 提取并反转义
|
||||||
|
String escapedXml = soapResponse.substring(startIdx + startTag.length(), endIdx); |
||||||
|
String unescapedXml = unescapeXml(escapedXml); |
||||||
|
|
||||||
|
log.debug("提取的业务响应:\n{}", unescapedXml); |
||||||
|
return unescapedXml; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* XML反转义(完整版) |
||||||
|
*/ |
||||||
|
private String unescapeXml(String text) { |
||||||
|
if (text == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
// 先替换字符实体(注意顺序:& 要最后处理,避免重复替换)
|
||||||
|
String result = text |
||||||
|
.replace("<", "<") |
||||||
|
.replace(">", ">") |
||||||
|
.replace(""", "\"") |
||||||
|
.replace("'", "'") |
||||||
|
.replace(" ", "\r") // 回车 CR (十进制)
|
||||||
|
.replace(" ", "\n") // 换行 LF (十进制)
|
||||||
|
.replace("
", "\r") // 回车 CR (十六进制小写)
|
||||||
|
.replace("
", "\r") // 回车 CR (十六进制大写)
|
||||||
|
.replace("
", "\n") // 换行 LF (十六进制小写)
|
||||||
|
.replace("
", "\n") // 换行 LF (十六进制大写)
|
||||||
|
.replace("&", "&"); // & 符号最后处理
|
||||||
|
|
||||||
|
// 可选:移除或替换特殊控制字符
|
||||||
|
result = result |
||||||
|
.replace("\r\n", "\n") // 统一换行符
|
||||||
|
.replace("\r", "\n"); // 单独的回车也转成换行
|
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 从XML中提取指定标签的值 |
||||||
|
*/ |
||||||
|
private String extractXmlValue(String xml, String tag) { |
||||||
|
if (xml == null || tag == null) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
String startTag = "<" + tag + ">"; |
||||||
|
String endTag = "</" + tag + ">"; |
||||||
|
|
||||||
|
int startIdx = xml.indexOf(startTag); |
||||||
|
if (startIdx == -1) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
int endIdx = xml.indexOf(endTag, startIdx); |
||||||
|
if (endIdx == -1) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
return xml.substring(startIdx + startTag.length(), endIdx); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* XML特殊字符转义 |
||||||
|
*/ |
||||||
|
private String escapeXml(String text) { |
||||||
|
if (text == null) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
return text.replace("&", "&") |
||||||
|
.replace("<", "<") |
||||||
|
.replace(">", ">") |
||||||
|
.replace("\"", """) |
||||||
|
.replace("'", "'"); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue