做了幾個呼叫三方簡訊平臺傳送簡訊的例子,大部分需要 攜帶引數,向指定URL傳送請求
回顧對接第一個平臺時痛苦的亂碼經歷,這裡放一份程式碼,算是個模版,再用到的時候過來copy一下就OK。
在進入主題之前,考慮一個編碼的問題:
1、unicode,utf8,gbk,gb2312之類的指的到底是什麼?為什麼需要它們?
字元編碼中ASCII、Unicode和UTF-8的區別 - 風行風中 - 部落格園 (cnblogs.com)
GB2312、GBK、GB18030 這幾種字符集的主要區別是什麼? - 知乎 (zhihu.com)
- 簡單來說,計算機只能識別0和1組成的二進位制,所以為了顯示某一個字元,必須指定字元與二進位制表示的對應關係。
- 各種各樣的字元會組合成一個集合,集合被稱為字元表,
- 給字元表裡的字元編上一個數字,也就是字元集合到一個整數集合的對映,這個整數集合叫做字符集,而按照字元二進位制表示標準進行的實現叫做編碼,我們需要它們的結合來讓螢幕顯示出我們看得懂的內容。
- 編碼其實就是一種對映關係,將位元組表示的值對映到字符集中的符號。
- unicode是一種字符集,涵蓋了世界上所有的字元,utf8是一種用於unicode的編碼方式
- gb2312是國內針對 ASCII 擴充套件的字符集,通常我們把編碼方案也叫做gb2312。GBK是對gb2312做的擴充套件。
也就是說,gbk,gb2312和 utf8 不是一個派系的。
2、程式執行時,處於記憶體中的字串是不是也具有指定的編碼?如果沒有,為什麼有時候在獲取位元組陣列時還要指定編碼方式?
這裡我看了一些文章,有了自己的理解,但是不知道理解的是否正確,先不列出來了
Get請求
- getResponse 內將資料寫入請求的方式
- 組織資料時對content進行URL編碼
- 正確設定content-type 頭
//呼叫處捕獲異常處理髮送失敗的情況,所以程式碼內不合預期的情況都是直接拋Exception
public void send(String to, String content) throws Exception {
//username,password,content,to...引數的非空 及 格式判斷
String apiRspStr = getResponse(to,content); //構建請求,獲取響應
String result = resolve(apiRspStr); //解析響應資料(kv,json,html...),
//成功時返回程式碼,失敗時返回錯誤訊息
if(!"0".equals(result)) { //"0" 需要按平臺文件替換
throw new Exception("訊息傳送失敗:" + result);
}
}
private String getResponse(String to, String content) throws Exception {
URLConnection con = null;
OutputStreamWriter out = null;
BufferedReader br = null;
String sendSmsData;
try {
sendSmsData = organizationData(to,content);
log.info("請求引數為:" + sendSmsData);
} catch (Exception e) {
log.error("組織請求資料時出現錯誤", e);
throw e;
}
try {
URL requestUrl = new URL(getUrl());
con = requestUrl.openConnection();
con.setDoOutput(true);
con.setRequestProperty("Pragma", "no-cache");
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=gb2312"); // 按簡訊平臺的要求設定 charset的值
out = new OutputStreamWriter(con.getOutputStream());
out.write(sendSmsData);
out.flush();
out.close();
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line = "";
StringBuffer buf = new StringBuffer();
while ( (line = br.readLine()) != null ) {
buf.append(line);
}
String responseStr = buf.toString();
log.info("響應資料:" + responseStr);
return responseStr;
} catch (IOException e) {
e.printStackTrace();
log.error("獲取響應失敗", e);
throw e;
} finally {
try {
if(out != null) {
out.close();
}
}catch(Exception e) {}
try {
if(br != null) {
br.close();
}
}catch(Exception e) {}
}
}
private String organizationData(String to, String content) throws Exception {
StringBuilder sendBuilder = new StringBuilder();
sendBuilder.append("username=");//使用者登入名
sendBuilder.append(getUserName());
sendBuilder.append("&password=");//密碼需要按平臺要求處理;
sendBuilder.append(hashpwd());
sendBuilder.append("&mobiles=");//接收手機號,限定不允許
sendBuilder.append(to);
sendBuilder.append("&content=");
sendBuilder.append(URLEncoder.encode(content, "GB2312"));
return sendBuilder.toString();
}
// resolve方法 依賴於簡訊平臺返回結果的標準,這裡提供的內容脫離平臺就沒有意義
//示例程式碼內 傳送成功result為0,傳送失敗會返回各種含義的數字,description是中文描述
private String resolve(String rspStr) throws Exception { //rspStr: result=0&description=%B7%A2%CB%CD%B3%C9%B9%A6&faillist=
String[] resultArray = rspStr.split("&");
Map kv = new HashMap();
for(String array : resultArray) {
String[] elementArray = array.split("=");
if(elementArray.length == 2) {
kv.put(elementArray[0], elementArray[1]);
}
}
if(kv.isEmpty()) {
log.error("rspStr: " + rspStr);
throw new Exception("解析返回資料時未得到結果");
}
String result = "";
if("0".equals(kv.get("result").toString())) {
result = "0";
return result;
}
result = URLDecoder.decode(kv.get("description").toString(),"gb2312") ;
return result;
}
Post請求
- 簡訊內容要用URL編碼
- 寫入請求體的資料以 List<NameValuePair> 形式組織
public void sendSmsPost(MsgData msgData){
String respContent;//響應報文
CloseableHttpClient httpClient = null;
try{
httpClient = HttpClients.createDefault(); //建立連線物件
HttpPost httpPost = new HttpPost(smsUrl); //建立post物件
Map params = new HashMap(); //構建請求引數
String phone = msgData.getMsgTo(); //接收手機號
String text = msgData.getContent(); //傳送內容
String gbkText = URLEncoder.encode(msgData.getContent().trim(), "GBK");
System.out.println("簡訊內容GBK:" + gbkText);
params.put("username",username);//登入使用者名稱
params.put("password",password);//登入使用者密碼
params.put("to",phone); //訊息接收手機號碼
params.put("text",gbkText);
List<NameValuePair> postParams = getParams(params);
httpPost.setHeader("Content-Type","application/x-www-form-urlencoded;charset=gbk");
httpPost.setEntity(new UrlEncodedFormEntity(postParams));
//傳送http請求,獲取返回結果
HttpResponse httpResponse = httpClient.execute(httpPost);
if(httpResponse.getStatusLine().getStatusCode() == 200){
//解析資料
respContent = EntityUtils.toString(httpResponse.getEntity());
System.out.println("響應資料:" + respContent);
}else {
//請求失敗
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(httpClient != null){
httpClient.close();
}
}catch (Exception e2){
e2.printStackTrace();
}
}
}
/**
* 引數解析
* @param map
* @return
*/
public static List<NameValuePair> getParams(Map<String, String> map){
List<NameValuePair> params = new ArrayList<NameValuePair>();
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> e : entrySet) {
String name = e.getKey();
String value = e.getValue();
NameValuePair pair = new BasicNameValuePair(name, value);
params.add(pair);
}
return params;
}