diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/Azdg.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/Azdg.java new file mode 100644 index 00000000..3a56432d --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/Azdg.java @@ -0,0 +1,149 @@ +package com.zdxt.enforcementcode.common.util; + +import java.security.MessageDigest; +import java.util.Base64; + +/** + * Azdg加密工具类 + * + * @author longshangbo@163.com + * + *

2019年11月18日 下午5:36:14

+ */ +public class Azdg { + + private static final String key = "chinagdn"; + + private static final Azdg INSTANCE = new Azdg(); + + /** + * 解密 + * @param cipherText 要解密的内容 + * @return 解密后的字符串 + */ + public static String decrypt(String cipherText) { + return INSTANCE.decrypt(cipherText, key); + } + + /** + * 加密 + * @param txt 要加密的内容 + * @return 加密后的字符串 + */ + public static String encrypt(String txt) { + return INSTANCE.encrypt(txt, key); + } + + /** + * 加密 + * @param txt + * @param key + * @return + */ + public String encrypt(String txt, String key) { + + String encrypt_key = "0f9cfb7a9acced8a4167ea8006ccd098"; + int ctr = 0; + String tmp = ""; + int i; + + for (i = 0; i < txt.length(); i++) { + ctr = (ctr == encrypt_key.length()) ? 0 : ctr; + tmp = tmp + encrypt_key.charAt(ctr) + (char) (txt.charAt(i) ^ encrypt_key.charAt(ctr)); + ctr++; + } + + return base64_encode(key(tmp, key)); + + } + + /** + * 解密 + * @param cipherText + * @param key + * @return + */ + public String decrypt(String cipherText, String key) { + + // base64解码 + cipherText = base64_decode(cipherText); + cipherText = key(cipherText, key); + String tmp = ""; + + for (int i = 0; i < cipherText.length(); i++) { + int c = cipherText.charAt(i) ^ cipherText.charAt(i + 1); + String x = "" + (char) c; + tmp += x; + i++; + } + return tmp; + } + + public String base64_decode(String str) { + +// sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); + + if (str == null) + return null; + return new String(Base64.getDecoder().decode(str)); + } + + public String key(String txt, String encrypt_key) { + + encrypt_key = strMD5(encrypt_key); + int ctr = 0; + String tmp = ""; + + for (int i = 0; i < txt.length(); i++) { + + ctr = (ctr == encrypt_key.length()) ? 0 : ctr; + int c = txt.charAt(i) ^ encrypt_key.charAt(ctr); + String x = "" + (char) c; + tmp = tmp + x; + ctr++; + + } + + return tmp; + + } + + public String base64_encode(String str) { + if (str == null) + return null; + return Base64.getEncoder().encodeToString(str.getBytes()); + } + + public static final String strMD5(String s) { + + char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + + try { + + byte[] strTemp = s.getBytes(); + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(strTemp); + byte[] md = mdTemp.digest(); + int j = md.length; + char str[] = new char[j * 2]; + int k = 0; + + for (int i = 0; i < j; i++) { + byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + + } + + return new String(str); + + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + + } + +} diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/ZwSmsClient.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/ZwSmsClient.java new file mode 100644 index 00000000..23d838ab --- /dev/null +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/ZwSmsClient.java @@ -0,0 +1,134 @@ +package com.zdxt.enforcementcode.common.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.axis.client.Call; +import org.apache.axis.client.Service; +import org.dromara.common.core.utils.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.xml.namespace.QName; +import javax.xml.rpc.ParameterMode; +import java.net.URL; + +/** + * 政务短信平台客户端(深圳政务短信 WebService) + *

+ * 账号密码由配置 sms.account / sms.pwd 提供(明文存储,发送前经 AZDG 加密)。 + */ +@Slf4j +@Component +public class ZwSmsClient { + + private static final QName OPERATION_INSERT_DOWN_SMS = new QName("", "InsertDownSms"); + private static final QName OPERATION_CONN_MAS = new QName("", "ConnMas"); + + /** + * 短信平台账号(明文,发送前经 AZDG 加密) + */ + @Value("${sms.account:}") + private String username; + + @Value("${sms.pwd:}") + private String password; + + /** + * 短信平台 WebService 地址 + */ + @Value("${sms.url:https://szsms.sz.gov.cn:8000/services/Sms}") + private String url; + + /** + * 批次号 + */ + @Value("${sms.batch:2409}") + private String batch; + + /** + * 异步发送短信,失败仅记录日志,不影响调用方主流程 + * + * @param phone 接收人手机号,多个逗号分隔 + * @param content 短信内容 + */ + @Async + public void asyncSendSms(String phone, String content) { + if (StringUtils.isBlank(phone) || StringUtils.isBlank(content)) { + log.warn("短信接收手机号或内容为空,跳过发送"); + return; + } + try { + String result = sendMessage(phone, content); + log.info("短信异步发送完成,phone={},平台返回:{}", phone, result); + } catch (Exception e) { + log.error("短信异步发送失败,phone={}", phone, e); + } + } + + /** + * 同步发送短信 + * + * @param phone 接收人手机号,多个逗号分隔 + * @param content 短信内容 + * @return 短信平台返回结果 + */ + public String sendMessage(String phone, String content) throws Exception { + if (StringUtils.isBlank(phone)) { + throw new IllegalArgumentException("短信接收手机号不能为空"); + } + if (StringUtils.isBlank(content)) { + throw new IllegalArgumentException("短信内容不能为空"); + } + if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { + throw new IllegalStateException("短信平台账号未配置(sms.account/sms.pwd)"); + } + Integer needReport = 1; + String sendbody = "\n" + + "\t\n" + + "\t%s" + + "" + + "" + + "%s\n" + + "\t\n" + + "\t\n" + + ""; + return invoke(OPERATION_INSERT_DOWN_SMS, + new String[]{"username", "password", "batch", "sendbody"}, + new Object[]{Azdg.encrypt(username), Azdg.encrypt(password), batch, + String.format(sendbody, phone.trim(), content, needReport)}); + } + + /** + * 验证账号密码(联调用,业务发送无需每次调用) + */ + public String connMas() throws Exception { + if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { + throw new IllegalStateException("短信平台账号未配置(sms.account/sms.pwd)"); + } + return invoke(OPERATION_CONN_MAS, + new String[]{"username", "password"}, + new Object[]{Azdg.encrypt(username), Azdg.encrypt(password)}); + } + + /** + * 统一的 Axis WebService 调用入口 + * + * @param operation 操作名 QName + * @param paramNames 参数名列表,与 args 一一对应 + * @param args 参数值列表 + */ + private String invoke(QName operation, String[] paramNames, Object[] args) throws Exception { + Service service = new Service(); + Call call = (Call) service.createCall(); + call.setTargetEndpointAddress(new URL(url)); + call.setOperationName(operation); + call.setTimeout(30_000); + for (int i = 0; i < paramNames.length; i++) { + call.addParameter(paramNames[i], org.apache.axis.encoding.XMLType.XSD_STRING, ParameterMode.IN); + } + call.setReturnType(org.apache.axis.encoding.XMLType.XSD_STRING); + String result = (String) call.invoke(args); + log.info("短信平台调用完成,operation={},返回:{}", operation.getLocalPart(), result); + return result; + } +}