package com.whdc.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.*; /** * @author lyf * @since 2025-06-25 */ @Component @Slf4j public class SmsHelper { @Value("${sms.url}") private String url; @Value("${sms.userName}") private String userName; @Value("${sms.serviceCode}") private String serviceCode; @Value("${sms.userPassword}") private String userPassword; @Autowired private HttpHelper httpHelper; public String send(List phones, String content) { return send(phones, content, "201"); } private String send(List phones, String content, String msgType) { if (phones == null || phones.size() == 0) { return "未选择手机号"; } if (content == null || content.length() == 0) { return "短信内容为空"; } String[] msgIds = new String[phones.size()]; for (int i = 0; i < phones.size(); i++) { msgIds[i] = UUID.randomUUID().toString().replace("-", ""); } String strPhones = String.join(",", phones); String strMsgIds = String.join(",", msgIds); String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); String sign = md5(userPassword + timestamp).toUpperCase(); Map params = new HashMap<>(); params.put("serviceCode", serviceCode); params.put("userName", userName); params.put("userPassword", userPassword); params.put("phones", strPhones); params.put("msgContent", encodeGBK(content)); params.put("timestamp", timestamp); params.put("sign", sign); params.put("mhtMsgIds", strMsgIds); params.put("sendTime", ""); params.put("priority", "5"); params.put("orgCode", "42"); params.put("msgType", msgType); params.put("reportFlag", "0"); String strResult = httpHelper.postFormUrlEncoded(url, params, null, Charset.forName("GBK")); if (strResult == null) { return "发送失败"; } // Map result = new ObjectMapper().readValue(strResult, Map.class); JSONObject result = JSON.parseObject(strResult); if (result == null) { return "发送结果解析失败"; } int errorCode = (Integer) result.get("result"); if (errorCode != 0) { return SmtpErrorCode.getErrorString(errorCode); } return "发送成功"; } private String md5(String str) { MessageDigest m; try { m = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } m.update(str.getBytes()); byte[] s = m.digest(); return parseByte2HexStr(s); } private static String encodeGBK(String content) { try { return URLDecoder.decode(content, "GBK"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } //将二进制数组转换成16进制字符串 private String parseByte2HexStr(byte[] buf) { StringBuilder sb = new StringBuilder(); for (byte b : buf) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex); } return sb.toString(); } public static class SmtpErrorCode { private static Map map; static { map = new HashMap<>(); map.put(100, "非法登录,如登录名、口令出错、登录名与口令不符,md5 值不匹配等。"); map.put(101, "连接过多,指单个商户要求同时建立的连接数过多。"); map.put(102, "登陆类型错。"); map.put(103, "协议版本号错"); map.put(104, "ip 不合法,请联系管理员绑定 ip 后才可正常使用"); map.put(105, "Smtp 的 tcp 协议只支持后付费类型"); map.put(201, "非法手机号码。"); map.put(202, "reportFlag 值不合法,值必须为 0 或 1"); map.put(203, "信息长度错"); map.put(204, "短信内容中有非法字符"); map.put(205, "短信内容太长"); map.put(206, "不存在的优先级"); map.put(207, "SUBMIT 命令中的 serviceCode 不合法或者过期"); map.put(208, "手机号和商户消息 id 个数不匹配"); map.put(209, "orgCode 字段超过规定长度"); map.put(210, "msgType 字段超过规定长度"); map.put(211, "http 提交短信时的 url 不正确"); map.put(212, "被代理的商户与代理商户之间的关系不合法"); map.put(213, "暂未开通此商户通道,或者商户通道名称配置错误"); map.put(214, "请求参数有误,比如传递了不在接口文档中定义的参数"); map.put(215, "被代理的商户 id 不存在"); map.put(216, "商户平台的消息 id 的长度超过最大长度"); map.put(217, "sendTime 参数时间戳格式不正确"); map.put(218, "商户服务代码与用户名密码不匹配"); map.put(219, "接口只支持 HTTP POST 方式提交,而您的请求为 HTTP GET 方式"); map.put(220, "批量提交一次最多只支持 50 个"); map.put(221, "手机号不能为空"); map.put(222, "短信内容含有乱码"); map.put(500, "系统内部失败"); map.put(900, "余额不足"); map.put(901, "发送速度太快"); } public static String getErrorString(int errorcode) { if (!map.containsKey(errorcode)) { return "errorcode:" + errorcode + "未定义"; } return map.get(errorcode); } } }