From 36bf25f295b11d6cbebd51473e9288e4afe23c86 Mon Sep 17 00:00:00 2001
From: 陈昶聿 <chychen@nbjetron.com>
Date: 星期一, 11 五月 2026 18:05:09 +0800
Subject: [PATCH] 【市一】湖滨短信发送
---
smartor/src/main/java/com/smartor/common/ShiyiSmsUtil.java | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 300 insertions(+), 0 deletions(-)
diff --git a/smartor/src/main/java/com/smartor/common/ShiyiSmsUtil.java b/smartor/src/main/java/com/smartor/common/ShiyiSmsUtil.java
new file mode 100644
index 0000000..724ffd6
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/common/ShiyiSmsUtil.java
@@ -0,0 +1,300 @@
+package com.smartor.common;
+
+import com.smartor.domain.ShiyiSmsRequest;
+import com.smartor.domain.ShiyiSmsResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 鏉窞甯備竴 HIS 鏈嶅姟骞冲彴瀵规帴宸ュ叿绫汇��
+ * <p>
+ * 鎸夈�奌IS 鏈嶅姟骞冲彴鎺ュ彛璇存槑鏂囨。 V1.1銆�3.1 鑺傜害瀹氾紝HIS 瀵瑰浠� WCF Web Service 褰㈠紡鍙戝竷锛�
+ * 缁熶竴鍏ュ彛锛歿@code int RunService(string TradeType, string TradeMsg, ref string TradeOut)}锛�
+ * 鍏朵腑 {@code TradeType} 鏍囪瘑涓氬姟缂栫爜锛寋@code TradeMsg} 涓� UTF-8 缂栫爜鐨� XML 鎶ユ枃銆�
+ * 鏈伐鍏风被鐩墠瀹炵幇 5.2 鐭俊涓氬姟 (TradeType=FASONGDX)銆�
+ */
+@Slf4j
+@Component
+public class ShiyiSmsUtil {
+
+ /** 5.2 鐭俊涓氬姟 TradeType */
+ public static final String TRADE_TYPE_FASONGDX = "FASONGDX";
+
+ /** WCF 鍛藉悕绌洪棿锛岄粯璁ら殢鏂囨。绀轰緥 */
+ private String namespace = "http://tempuri.org/";
+
+ /** 榛樿鎿嶄綔鍛樹唬鐮� */
+ @Value("${his.service.defaultCaozuoydm:}")
+ private String defaultCaozuoydm;
+
+ /** 榛樿鎿嶄綔鍛樺鍚� */
+ @Value("${his.service.defaultCaozuoyxm:}")
+ private String defaultCaozuoyxm;
+
+ /** 榛樿绯荤粺鏍囪瘑 */
+ private String defaultXitongbs = "0";
+
+ /** 榛樿鍒嗛櫌浠g爜 */
+ private String defaultFenyuandm = "1";
+
+ /** 榛樿鏈烘瀯浠g爜 */
+ private String defaultJigoudm = "1";
+
+ private final RestTemplate restTemplate = new RestTemplate();
+
+ /**
+ * 鍙戦�佺煭淇� (FASONGDX)
+ */
+ public ShiyiSmsResponse sendSms(ShiyiSmsRequest request) {
+ if (request == null) {
+ throw new IllegalArgumentException("鐭俊璇锋眰涓嶈兘涓虹┖");
+ }
+ if (StringUtils.isBlank(request.getShoujihao())) {
+ throw new IllegalArgumentException("鎵嬫満鍙蜂笉鑳戒负绌�");
+ }
+ if (StringUtils.isBlank(request.getDuanxinnr())) {
+ throw new IllegalArgumentException("鐭俊鍐呭涓嶈兘涓虹┖");
+ }
+
+ applyDefaults(request);
+
+ String tradeMsg = buildFasongdxXml(request);
+ log.info("甯備竴 鐭俊璇锋眰, TradeType={}, TradeMsg={}", TRADE_TYPE_FASONGDX, tradeMsg);
+
+ String tradeOut = invokeRunService(TRADE_TYPE_FASONGDX, tradeMsg);
+ log.info("甯備竴 鐭俊鍝嶅簲, TradeOut={}", tradeOut);
+
+ return parseFasongdxResponse(tradeOut);
+ }
+
+ /**
+ * 璋冪敤 甯備竴 WCF RunService 鎺ュ彛銆係OAP 1.1 鍩虹閴存潈鎸夋枃妗d笉瑕佹眰銆�
+ *
+ * @return TradeOut 鎶ユ枃锛堟湇鍔$ ref 鍙傛暟锛�
+ */
+ public String invokeRunService(String tradeType, String tradeMsg) {
+ String soapEnvelope = buildSoapEnvelope(tradeType, tradeMsg);
+ String hisServiceUrl = "http://192.200.54.57:7790/MediInfoHis.svc";
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(new MediaType("text", "xml", StandardCharsets.UTF_8));
+ headers.set("SOAPAction", joinNamespace(namespace, "IMediInfoHis/RunService"));
+
+ HttpEntity<String> entity = new HttpEntity<>(soapEnvelope, headers);
+ try {
+ ResponseEntity<String> response = restTemplate.postForEntity(hisServiceUrl, entity, String.class);
+ String body = response.getBody();
+ if (StringUtils.isBlank(body)) {
+ throw new RuntimeException("HIS 杩斿洖绌哄搷搴�");
+ }
+ return extractTradeOut(body);
+ } catch (Exception e) {
+ log.error("璋冪敤 HIS RunService 澶辫触, url={}, tradeType={}, err={}", hisServiceUrl, tradeType, e.getMessage(), e);
+ throw new RuntimeException("璋冪敤 HIS RunService 澶辫触: " + e.getMessage(), e);
+ }
+ }
+
+ private void applyDefaults(ShiyiSmsRequest request) {
+ if (StringUtils.isBlank(request.getCaozuoydm())) {
+ request.setCaozuoydm(defaultCaozuoydm);
+ }
+ if (StringUtils.isBlank(request.getCaozuoyxm())) {
+ request.setCaozuoyxm(defaultCaozuoyxm);
+ }
+ if (StringUtils.isBlank(request.getCaozuorq())) {
+ request.setCaozuorq(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ }
+ if (StringUtils.isBlank(request.getXitongbs())) {
+ request.setXitongbs(defaultXitongbs);
+ }
+ if (StringUtils.isBlank(request.getFenyuandm())) {
+ request.setFenyuandm(defaultFenyuandm);
+ }
+ if (StringUtils.isBlank(request.getJigoudm())) {
+ request.setJigoudm(defaultJigoudm);
+ }
+ if (StringUtils.isBlank(request.getDuanxinlx())) {
+ request.setDuanxinlx("0");
+ }
+ }
+
+ private String buildFasongdxXml(ShiyiSmsRequest r) {
+ StringBuilder sb = new StringBuilder(512);
+ sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+ sb.append("<FASONGDX_IN>");
+ sb.append("<BASEINFO>");
+ appendTag(sb, "CAOZUOYDM", r.getCaozuoydm());
+ appendTag(sb, "CAOZUOYXM", r.getCaozuoyxm());
+ appendTag(sb, "CAOZUORQ", r.getCaozuorq());
+ appendTag(sb, "XITONGBS", r.getXitongbs());
+ appendTag(sb, "FENYUANDM", r.getFenyuandm());
+ appendTag(sb, "JIGOUDM", r.getJigoudm());
+ appendTag(sb, "JIGOUMC", r.getJigoumc());
+ appendTag(sb, "JIGOUYZM", r.getJigouyzm());
+ appendTag(sb, "JIESHOUJGDM", r.getJieshoujgdm());
+ appendTag(sb, "ZHONGDUANJB", r.getZhongduanjb());
+ appendTag(sb, "ZHONGDUANLS", r.getZhongduanls());
+ appendTag(sb, "IPADDRESS", r.getIpaddress());
+ appendTag(sb, "YEWULX", r.getYewulx());
+ appendTag(sb, "JIERUCSDM", r.getJierucsdm());
+ sb.append("</BASEINFO>");
+ appendTag(sb, "DUANXINLX", r.getDuanxinlx());
+ appendTag(sb, "SHOUJIHAO", r.getShoujihao());
+ appendTag(sb, "DUANXINNR", r.getDuanxinnr());
+ sb.append("</FASONGDX_IN>");
+ return sb.toString();
+ }
+
+ private ShiyiSmsResponse parseFasongdxResponse(String xml) {
+ ShiyiSmsResponse resp = new ShiyiSmsResponse();
+ resp.setRawXml(xml);
+ if (StringUtils.isBlank(xml)) {
+ resp.setErrno("-1");
+ resp.setErrmsg("HIS 杩斿洖绌� TradeOut");
+ return resp;
+ }
+ try {
+ Document doc = parseXml(xml);
+ resp.setErrno(readTag(doc, "ERRNO"));
+ resp.setErrmsg(readTag(doc, "ERRMSG"));
+ resp.setErrmsgex(readTag(doc, "ERRMSGEX"));
+ resp.setMessageId(readTag(doc, "MessageID"));
+ resp.setDuanxinid(readTag(doc, "DUANXINID"));
+ } catch (Exception e) {
+ log.error("瑙f瀽 HIS 鐭俊鍝嶅簲澶辫触, xml={}, err={}", xml, e.getMessage(), e);
+ resp.setErrno("-1");
+ resp.setErrmsg("瑙f瀽鍝嶅簲澶辫触: " + e.getMessage());
+ }
+ return resp;
+ }
+
+ private String buildSoapEnvelope(String tradeType, String tradeMsg) {
+ // WCF 榛樿 BasicHttpBinding 涓嬫帴鍙f柟娉曚互 Message Contract 褰㈠紡鍙戝竷锛屽弬鏁拌妭鐐瑰悕涓� C# 鏂规硶绛惧悕涓�鑷淬��
+ // TradeOut 涓� ref 鍙傛暟锛屽叆鍙備篃闇�浼犵┖鍏冪礌鍗犱綅銆�
+ return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:t=\"" + namespace + "\">"
+ + "<s:Body>"
+ + "<t:RunService>"
+ + "<t:TradeType>" + escapeXml(tradeType) + "</t:TradeType>"
+ + "<t:TradeMsg>" + escapeXml(tradeMsg) + "</t:TradeMsg>"
+ + "<t:TradeOut></t:TradeOut>"
+ + "</t:RunService>"
+ + "</s:Body>"
+ + "</s:Envelope>";
+ }
+
+ private String extractTradeOut(String soapResponse) throws Exception {
+ Document doc = parseXml(soapResponse);
+ // TradeOut 鑺傜偣 (甯﹀懡鍚嶇┖闂�)
+ String tradeOut = readTagIgnoreNs(doc, "TradeOut");
+ if (StringUtils.isBlank(tradeOut)) {
+ // 鏈変簺 WCF 瀹炵幇浼氭妸 ref 鍙傛暟杈撳嚭鑺傜偣鍛藉悕涓� RunServiceResult 鐨勫悓绾� TradeOut
+ tradeOut = readTagIgnoreNs(doc, "tradeOut");
+ }
+ return tradeOut;
+ }
+
+ private Document parseXml(String xml) throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(false);
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return builder.parse(new InputSource(new StringReader(xml)));
+ }
+
+ private String readTag(Document doc, String name) {
+ NodeList list = doc.getElementsByTagName(name);
+ if (list.getLength() == 0) {
+ return null;
+ }
+ return list.item(0).getTextContent();
+ }
+
+ private String readTagIgnoreNs(Document doc, String localName) {
+ NodeList all = doc.getElementsByTagName("*");
+ for (int i = 0; i < all.getLength(); i++) {
+ Node node = all.item(i);
+ if (node instanceof Element) {
+ Element el = (Element) node;
+ String local = el.getLocalName() != null ? el.getLocalName() : el.getNodeName();
+ if (local.equalsIgnoreCase(localName) || local.endsWith(":" + localName)) {
+ return el.getTextContent();
+ }
+ if (el.getNodeName().endsWith(":" + localName) || el.getNodeName().equalsIgnoreCase(localName)) {
+ return el.getTextContent();
+ }
+ }
+ }
+ return null;
+ }
+
+ private void appendTag(StringBuilder sb, String tag, String value) {
+ sb.append('<').append(tag).append('>');
+ if (StringUtils.isNotBlank(value)) {
+ sb.append(escapeXml(value));
+ }
+ sb.append("</").append(tag).append('>');
+ }
+
+ private String escapeXml(String input) {
+ if (input == null) {
+ return "";
+ }
+ StringBuilder out = new StringBuilder(input.length());
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+ switch (c) {
+ case '&':
+ out.append("&");
+ break;
+ case '<':
+ out.append("<");
+ break;
+ case '>':
+ out.append(">");
+ break;
+ case '"':
+ out.append(""");
+ break;
+ case '\'':
+ out.append("'");
+ break;
+ default:
+ out.append(c);
+ }
+ }
+ return out.toString();
+ }
+
+ private String joinNamespace(String ns, String op) {
+ if (ns == null) {
+ return "\"" + op + "\"";
+ }
+ if (ns.endsWith("/")) {
+ return "\"" + ns + op + "\"";
+ }
+ return "\"" + ns + "/" + op + "\"";
+ }
+}
--
Gitblit v1.9.3