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("&amp;");
+                    break;
+                case '<':
+                    out.append("&lt;");
+                    break;
+                case '>':
+                    out.append("&gt;");
+                    break;
+                case '"':
+                    out.append("&quot;");
+                    break;
+                case '\'':
+                    out.append("&apos;");
+                    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