因為客戶需要,本身使用的 阿里雲的短信服務改為了中國移動MAS HTTP 1.0 短信通知,因為看到網絡上關於此類的博客知識很少,再趟完坑后特地寫下這篇博客,提醒后來人。
特別感謝 中國移動MAS 客服 @左立,可能你看不到,非常感謝你 不厭其煩的回答!!
首先創建 接口,用戶類型是HTTP
然后下載文檔,下載簽名:
這里簡單說一下流程: HTTP 1.0 的通訊方式是,
1. 先向中國移動 發送 企業名、接口名、接口密碼,實現登錄操作。中國移動返回登錄id 和密鑰。
2. 攜帶中國移動返回的密鑰和 所需要的信息進行第二次的 請求,此次請求就是發送短信的請求。
根據文檔書寫所需要的發送短信的工具類:
1 public class HttpSend { 2 private static String ec_name = "山東*****" ; // 企業名 3 private static String user_name = "***" ; // 接口賬號 4 private static String user_passwd = "****" ; // 接口賬號密碼 5 private static String sign = "*****" ; //簽名編號 6 private static String serial = "" ; // 擴展碼 7 private static String checkUrl = "http://mas.ecloud.10086.cn/app/http/authorize" ; // 身份驗證url 8 private static String sendUrl = "http://mas.ecloud.10086.cn/app/http/sendSms" ; // 發送信息的url 9 10 // 身份驗證方法 11 public static CheckRes check (){ 12 String req = "ec_name="+ec_name+"&user_name="+user_name+"&user_passwd="+user_passwd ; 13 System.out.println("傳入參數:"+req); 14 HttpRequest httpRequest = new HttpRequest() ; 15 String checkStr = httpRequest.sendPost(checkUrl,req) ; //返回驗證信息的 回參 16 System.out.println("驗證身份結果:"+checkStr); 17 CheckRes checkRes = JSONUtils.json2pojo(checkStr,CheckRes.class); 18 String mas_user_id = checkRes.getMas_user_id() ; 19 System.out.println("mas_user_id:"+mas_user_id); 20 return checkRes ; 21 } 22 23 // 發送短信 方法,需要使用到 check()方法的 返回值 CheckRes 24 public static Boolean send (CheckRes checkRes ,String mobiles ,String content){ 25 String temporary = checkRes.getMas_user_id() + mobiles + content + sign + serial + checkRes.getAccess_token() ; // 存放要進行加密的信息 26 String mac = MD5Util.getMD5Up(temporary) ; //加密 27 String sendReq = "mas_user_id="+checkRes.getMas_user_id()+"&mobiles="+mobiles+"&content="+content+"&sign="+sign+"&serial="+serial+"&mac="+mac; 28 HttpRequest httpRequest = new HttpRequest() ; 29 String sendStr = httpRequest.sendPost(sendUrl,sendReq) ; //發送 普通短信 30 System.out.println("發送結果:"+sendStr); 31 String[] test = sendStr.split(",",0); // 將字符串 按照 逗號分隔,取前面一段 32 if (test[0].equals("{\"RET-CODE\":\"SC:0000\"")){ // 直接進行比較 33 return true ; 34 }else { 35 return false ; 36 } 37 38 } 39 40 // 測試 main函數 41 public static void main(String[] args){ 42 CheckRes result = check() ; 43 Boolean b =send(result,"15610446589","益羊鐵路測試短信"); 44 if (b){ 45 System.out.println("成功"); 46 }else { 47 System.out.println("失敗"); 48 } 49 } 50 51 }
這里用到的工具 HttpRequest ,用於攜帶參數請求頁面:
public class HttpRequest { /** * 向指定URL發送GET方法的請求 * * @param url * 發送請求的URL * @param param * 請求參數,請求參數應該是 name1=value1&name2=value2 的形式。 * @return URL 所代表遠程資源的響應結果 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打開和URL之間的連接 URLConnection connection = realUrl.openConnection(); // 設置通用的請求屬性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立實際的連接 connection.connect(); // 獲取所有響應頭字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍歷所有的響應頭字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定義 BufferedReader輸入流來讀取URL的響應 in = new BufferedReader(new InputStreamReader( connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("發送GET請求出現異常!" + e); e.printStackTrace(); } // 使用finally塊來關閉輸入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 向指定 URL 發送POST方法的請求 * * @param url * 發送請求的 URL * @param param * 請求參數,請求參數應該是 name1=value1&name2=value2 的形式。 * @return 所代表遠程資源的響應結果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打開和URL之間的連接 URLConnection conn = realUrl.openConnection(); // 設置通用的請求屬性 // conn.setRequestProperty("accept", "*/*"); // conn.setRequestProperty("connection", "Keep-Alive"); // conn.setRequestProperty("user-agent", // "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 發送POST請求必須設置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); // 獲取URLConnection對象對應的輸出流 out = new PrintWriter(conn.getOutputStream()); // 發送請求參數 out.print(param); // flush輸出流的緩沖 out.flush(); // 定義BufferedReader輸入流來讀取URL的響應 in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("發送 POST 請求出現異常!"+e); e.printStackTrace(); } //使用finally塊來關閉輸出流、輸入流 finally{ try{ if(out!=null){ out.close(); } if(in!=null){ in.close(); } } catch(IOException ex){ ex.printStackTrace(); } } return result; } }
JSONUtils工具:
public class JSONUtils { private final static ObjectMapper objectMapper = new ObjectMapper(); private static Logger log = LoggerFactory.getLogger(JSONUtils.class); private JSONUtils() { } public static ObjectMapper getInstance() { return objectMapper; } public static String obj2json(Object obj) { try { return objectMapper.writeValueAsString(obj); } catch (JsonProcessingException e) { // TODO Auto-generated catch block log.error(e.getMessage()); } return null; } public static <T> T json2pojo(String jsonStr, Class<T> clazz) { try { return objectMapper.readValue(jsonStr, clazz); } catch (JsonParseException e) { // TODO Auto-generated catch block log.error(e.getMessage()); } catch (JsonMappingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }
MD5工具,加密使用大寫的 MD5加密方式
public class MD5Util { public static String getMD5(String value) { String s = null; char hexDigits[] = { // 用來將字節轉換成 16 進制表示的字符 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; try { java.security.MessageDigest md = java.security.MessageDigest .getInstance("MD5"); md.update(value.getBytes()); // MD5 的計算結果是一個 128 位的長度整數, byte tmp[] = md.digest(); // 用字節表示就是 16 個字節 char str[] = new char[16 * 2]; // 每個字節用 16 進制表示的話,使用兩個字符, // 所以表示成 16 進制需要 32 個字符 int k = 0; // 表示轉換結果中對應的字符位置 for (int i = 0; i < 16; i++) { // 從第一個字節開始,對 MD5 的每一個字節 // 轉換成 16 進制字符的轉換 byte byte0 = tmp[i]; // 取第 i 個字節 str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字節中高 4 位的數字轉換, // >>> 為邏輯右移(即無符號右移),將符號位一起右移 // 取字節中低 4 位的數字轉換 str[k++] = hexDigits[byte0 & 0xf]; } s = new String(str); // 換后的結果轉換為字符串 } catch (Exception e) { e.printStackTrace(); } return s; } // MD5大寫 public static String getMD5Up(String value) { String s = null; char hexDigits[] = { // 用來將字節轉換成 16 進制表示的字符 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; try { java.security.MessageDigest md = java.security.MessageDigest .getInstance("MD5"); md.update(value.getBytes()); // MD5 的計算結果是一個 128 位的長度整數, byte tmp[] = md.digest(); // 用字節表示就是 16 個字節 char str[] = new char[16 * 2]; // 每個字節用 16 進制表示的話,使用兩個字符, // 所以表示成 16 進制需要 32 個字符 int k = 0; // 表示轉換結果中對應的字符位置 for (int i = 0; i < 16; i++) { // 從第一個字節開始,對 MD5 的每一個字節 // 轉換成 16 進制字符的轉換 byte byte0 = tmp[i]; // 取第 i 個字節 str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字節中高 4 位的數字轉換, // >>> 為邏輯右移(即無符號右移),將符號位一起右移 // 取字節中低 4 位的數字轉換 str[k++] = hexDigits[byte0 & 0xf]; } s = new String(str); // 換后的結果轉換為字符串 } catch (Exception e) { e.printStackTrace(); } return s; } /** * 判斷字符串的md5校驗碼是否與一個已知的md5碼相匹配 * * @param md5 要校驗的字符串 * @param md5PwdStr 已知的md5校驗碼 */ public static boolean checkPassword(String md5, String md5PwdStr) { return md5.equals(md5PwdStr); } }
這里注意的是 ,這兩次的請求都是 post 請求。
要注意拼接字符串以及加密的字符串 的順序是不能亂的!!
最后再次感謝 @左立