做了幾個調用三方短信平台發送短信的例子,大部分需要 攜帶參數,向指定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;
}