package com.ruoyi.common.utils; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.utils.http.HttpUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 短信发送工具类 * 参考PHP版本的SmsUtils实现 * * @author ruoyi * @date 2025-12-07 */ public class SmsUtils { private static final Logger log = LoggerFactory.getLogger(SmsUtils.class); /** * 发送 POST 请求 * * @param url 服务器地址 * @param data 请求参数 * @return 响应内容 * @throws IOException */ public static String post(String url, String data) throws IOException { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setDoOutput(true); try (OutputStream os = connection.getOutputStream()) { os.write(data.getBytes(StandardCharsets.UTF_8)); os.flush(); } StringBuilder response = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { response.append(line); } } return response.toString(); } /** * 计算 MD5 值 * * @param str 字符串 * @return MD5 值 * @throws NoSuchAlgorithmException */ public static String md5(String str) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] array = md.digest(str.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (byte item : array) { sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); } return sb.toString(); } /** * 获取当前时间戳(毫秒) * * @return 时间戳字符串 */ public static Long getTimestamp() { return System.currentTimeMillis(); } /** * 生成签名 * 签名算法:MD5(userName + password + timestamp) * * @param userName 用户名 * @param password 密码 * @param timestamp 时间戳 * @return 签名字符串 */ public static String generateSign(String userName, String password, Long timestamp) throws NoSuchAlgorithmException { // 时间戳 // 计算 sign 参数 String sign = md5(userName + timestamp + md5(password)); return sign; } /** * 发送HTTP POST请求 * * @param url 请求地址 * @param data 请求数据 * @return 响应结果 */ public static JSONObject sendPost(String url, Map data) { try { String jsonData = JSON.toJSONString(data); log.debug("短信API请求,URL:{},数据:{}", url, jsonData); String response = post(url,jsonData);;//HttpUtils.sendPost(url, jsonData, "application/json"); log.debug("短信API响应:{}", response); if (StringUtils.isNotEmpty(response)) { return JSON.parseObject(response); } } catch (Exception e) { log.error("短信API请求失败,URL:{}", url, e); } return null; } /** * 群发短信 * * @param address 短信服务地址 * @param userName 账号 * @param password 密码 * @param phoneList 手机号列表,多个用逗号分隔 * @param content 短信内容 * @return 发送结果 */ public static JSONObject sendSmsMass(String address, String userName, String password, String phoneList, String content) throws NoSuchAlgorithmException{ Long timestamp = getTimestamp(); String sign = generateSign(userName, password, timestamp); String url = "http://" + address + "/sms/api/sendMessageMass"; Map data = new HashMap<>(); data.put("userName", userName); data.put("content", content); data.put("phoneList", phoneList); data.put("timestamp", timestamp); data.put("sign", sign); data.put("sendTime", ""); data.put("extCode", ""); data.put("callData", ""); return sendPost(url, data); } /** * 单条/点对点短信发送 * * @param address 短信服务地址 * @param userName 账号 * @param password 密码 * @param messageList 消息列表 [{phone: "手机号", content: "内容"}, ...] * @return 发送结果 */ public static JSONObject sendSmsOne(String address, String userName, String password, List> messageList) throws NoSuchAlgorithmException { Long timestamp = getTimestamp(); String sign = generateSign(userName, password, timestamp); String url = "http://" + address + "/sms/api/sendMessageOne"; Map data = new HashMap<>(); data.put("userName", userName); data.put("timestamp", timestamp); data.put("sign", sign); data.put("messageList", messageList); return sendPost(url, data); } /** * 发送单条短信(简化方法) * * @param address 短信服务地址 * @param userName 账号 * @param password 密码 * @param phone 手机号 * @param content 短信内容 * @return 发送结果 */ public static JSONObject sendSms(String address, String userName, String password, String phone, String content) throws NoSuchAlgorithmException{ List> messageList = new ArrayList<>(); messageList.add(new HashMap() {{ put("phone", phone); put("content", content); }}); return sendSmsOne(address, userName, password, messageList); } /** * 查询账户余额 * * @param address 短信服务地址 * @param userName 账号 * @param password 密码 * @return 余额信息 */ public static JSONObject getBalance(String address, String userName, String password) throws NoSuchAlgorithmException { Long timestamp = getTimestamp(); String sign = generateSign(userName, password, timestamp); String url = "http://" + address + "/sms/api/getBalance"; Map data = new HashMap<>(); data.put("userName", userName); data.put("timestamp", timestamp); data.put("sign", sign); return sendPost(url, data); } /** * 获取发送报告 * * @param address 短信服务地址 * @param userName 账号 * @param password 密码 * @return 发送报告 */ public static JSONObject getReport(String address, String userName, String password) throws NoSuchAlgorithmException { Long timestamp = getTimestamp(); String sign = generateSign(userName, password, timestamp); String url = "http://" + address + "/sms/api/getReport"; Map data = new HashMap<>(); data.put("userName", userName); data.put("timestamp", timestamp); data.put("sign", sign); return sendPost(url, data); } }