在進行短信發送的接口,因廠家不同,有的廠家會采用報文的格式進行短信請求的發送與接收。本文主要介紹利用HttpURLConnection進行短信報文的請求與響應。
一般的url請求分為兩種,一種是GET,一種是POST:
1.GET請求的參數是放在url后面拼接的,請求大小有限制,具體多少大家可以自行去百度,在這里就不多說了
2.POST請求參數是放在HTTP請求的正文里的,可傳輸的內容遠大於GET請求,而且理論上來說POST請求是沒有大小限制的,所以使用POST請求較多
一般正常的請求,get參數會顯示在地址欄上,參數很容易被獲取,安全性也較低,所以使用POST請求會比較好
HttpURLConnection有兩種簡單的設置請求頭的方法
setRequestProperty(key,value)
addRequestProperty(key,value)
setRequestProperty和addRequestProperty的區別就是,setRequestProperty會覆蓋已經存在的key的所有values,有清零重新賦值的作用。而addRequestProperty則是在原來key的基礎上繼續添加其他value。
發送報文格式如圖所示:
短信發送:
try {
String postXml = "<?xml version='1.0' encoding='UTF-8'?>"; postXml = postXml + "<mtpacket>"; postXml = postXml + "<cpid>" +ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_CPID)+ "</cpid>"; postXml = postXml + "<userpass>" + ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_USERPASS) + "</userpass>"; postXml = postXml + "<port>" + ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_PORT)+ "</port>"; postXml = postXml + "<respDataType>XML</respDataType>"; postXml = postXml + "<cpmid>" + ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_CPMID)+ "</cpmid>"; postXml = postXml + "<flag>1</flag>"; postXml = postXml + "<mobile><![CDATA[" + mobile + "]]></mobile>"; postXml = postXml + "<message><![CDATA[" + new String(content.getBytes(), "utf-8") + "]]></message>"; postXml = postXml + "</mtpacket>"; logger.info("發送url:{},發送內容:{}",ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_POSTURL), postXml);
//1.連接的URL URL url = new URL(ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_POSTURL));
//2.這個地方的conn是根據請求協議(此處是http協議)生成的URLConnection類的子類HttpURLConnection
//所以將其轉化為HttpURLConnection類,以便使用HttpURLConnection更過的API HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//3.POST可以更好的傳參 conn.setRequestMethod("POST");
//4.是否使用緩存,Post 請求不能使用緩存 conn.setUseCaches(false);
//5.設置之后可以向服務端寫入數據、、可以使用conn.getOutputStream().write()
// 可以傳輸參數,POST請求數據放在正文內,所以需要開啟傳參 conn.setDoOutput(true);
//6.http讀取數據
// 默認是true,所以可以一般的請求都可以獲取數據
urlConnection.setDoInput(true);
//7.設置請求頭 conn.setRequestProperty("Content-type", "text/xml;charset=UTF-8");
//8.輸出流,進行傳參,所有數據放在這里 OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
//9.寫入參數內容 out.write(postXml);
//10.刷新輸出流,把所有的數據流數據都傳輸過去 out.flush();
//11.關閉輸出流 out.close();
}catch (Exception e){
e.printStackTrace();
}
接收短信報文:
接收短信代碼:
if (conn.getResponseCode() != 200) { logger.info("發送失敗:返回狀態:" + conn.getResponseCode()); } String result = "";
//獲取輸入流,這段是正式請求,會把所有的設置和參數以http方式進行請求 BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "GBK")); String line; while ((line = in.readLine()) != null) { result = result + line + "\n"; } in.close(); String re = result.trim().replaceAll("'", "\"");
//打印獲取的數據 logger.info("請求返回:" + re); if (!re.contains("<respCode>0</respCode>")) { logger.info("發送失敗:返回:" + re); }
完整示例代碼:
@Override public void sendSms(String mobile, String content, Map<String, Object> params) { try { String postXml = "<?xml version='1.0' encoding='UTF-8'?>"; postXml = postXml + "<mtpacket>"; postXml = postXml + "<cpid>" +ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_CPID)+ "</cpid>"; postXml = postXml + "<userpass>" + ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_USERPASS) + "</userpass>"; postXml = postXml + "<port>" + ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_PORT)+ "</port>"; postXml = postXml + "<respDataType>XML</respDataType>"; postXml = postXml + "<cpmid>" + ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_CPMID)+ "</cpmid>"; postXml = postXml + "<flag>1</flag>"; postXml = postXml + "<mobile><![CDATA[" + mobile + "]]></mobile>"; postXml = postXml + "<message><![CDATA[" + new String(content.getBytes(), "utf-8") + "]]></message>"; postXml = postXml + "</mtpacket>"; logger.info("發送url:{},發送內容:{}",ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_POSTURL), postXml); URL url = new URL(ZkjnSmsConfig.getConfigValue(ZkjnSmsConfig.SMS_ZKJN_POSTURL)); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("POST"); conn.setUseCaches(false); conn.setDoOutput(true); conn.setRequestProperty("Content-type", "text/xml;charset=UTF-8"); OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); out.write(postXml); out.flush(); out.close(); if (conn.getResponseCode() != 200) { logger.info("發送失敗:返回狀態:" + conn.getResponseCode()); } String result = ""; BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "GBK")); String line; while ((line = in.readLine()) != null) { result = result + line + "\n"; } in.close(); String re = result.trim().replaceAll("'", "\""); logger.info("請求返回:" + re); if (!re.contains("<respCode>0</respCode>")) { logger.info("發送失敗:返回:" + re); } }catch (Exception e){ e.printStackTrace(); } }
注意事項:
1.set一些設置的時候必須在connection之前,如果在connection之后這些set都沒有效果了
2.post請求的正文是通過outputStream流寫入的,但是在這並沒有真正的去發送請求,只是放在了內存緩沖區,只有當getInputStream()調用的時候才真正的去請求
3.設置超時,防止網絡異常的情況下,可能會導致程序僵死而不繼續往下執行
//超時設置必須在connection之前
urlConnection.setConnectTimeout(5 * 1000);// 5秒連接超時
urlConnection.setReadTimeout(5 * 1000);// 5秒獲取內容超時
4.添加請求頭的時候如果有中文,就有可能造成中文亂碼這時候可以使用這個方法
// 參數進行encode(編碼),防止中文亂碼
urlConnection.setRequestProperty("test", URLEncoder.encode("一個測試請求頭", "UTF-8"));
對某個參數進行URLEncoder.encode,服務端獲取參數之后再通過URLDecoder.decode一下就可以獲得完整的中文了
5.如果環境是采用GBK編碼,而短信是采用utf-8中文英文數字組合的方式組織的,這個時候要注意。要做一下操作
首先要將中文字符進行轉換,
postXml = postXml + "<message><![CDATA[" + new String(content.getBytes("UTF-8"),"UTF-8") + "]]></message>";
其次在進行流輸出的時候,要設定輸出字符,否則在轉換的時候,容易出現,字符不匹配出現亂碼的問題【環境GBK,流輸出默認是采用環境編碼的】:
OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(),Charset.forName("UTF-8"));