最近項目中遇到用java程序通過中國聯通G網短信平臺發送長短信的需求,所謂長短信就是將內容超過70個字符的短消息拆分成多條70字符以內的短信分別發送,而在用戶的手機上將所有的內容在一條消息中顯示出來。因為我之前一直是做j2ee開發的,對短信這一塊并不熟悉,拿到需求之后請教了幾位做SP的朋友。從他們哪里得知運營商處理短信發送有兩種方式,移動采取CMPP協議、聯通采用SGIP協議,由于這兩個協議都是由所謂SMPP協議派生出來的,所以兩者許多共同之處。雖然如此在項目實施過程中仍然遇到了一些問題,鑒于blogjava鼓勵原創的風格,也嘗試寫一篇小文,記錄解決這些問題的過程,希望對需要的朋友有幫助,也簡單總結一下本人在調用他人jar包和處理java編碼問題時積累的一點小經驗,有不當之處請朋友們指正。
一、關于spapi.jar短信發送包br /> 要讓用戶的手機能夠識別該短信是否是長短信,根據協議規定,應在內容字段中增加包頭:
包頭一共6個字節,如下:
1、字節一:包頭長度,固定填寫0x05;
2、字節二:包頭類型標識,固定填寫0x00,表示長短信;
3、字節三:子包長度,固定填寫0x03,表示后面三個字節的長度;
4、字節四到字節六:包內容:
1)字節四:長消息參考號,每個SP給每個用戶發送的每條參考號都應該不同,可以從0開始,每次加1,最大255,便于同一個終端對同一個SP的消息的不同的長短信進行識別;
2)字節五:本條長消息的的總消息數,從1到255,一般取值應該大于2;
3)字節六:本條消息在長消息中的位置或序號,從1到255,第一條為1,第二條為2,最后一條等于第四字節的值。
包頭和內容部分經過本人試驗必須采用UCS2也就是Unicode編碼方式發送給短信網關,發送過程采用spapi.jar包中的spApi.Submit類的對象綁定Socket流的方式。這里要特別指出,Submit類的默認初始化方法對編碼方式和字符緩沖區進行了區分,造成UCS2編碼發送短信時加上包頭后手機顯示亂碼。所幸該類還提供了setContent()方法,只要通過該方法以指定的編碼方式傳入String型的短信內容,即可解決亂碼問題。
Submit submit = null;
.......//獲得輸入輸出流,可參考spapi.jar示例程序

submit = new Submit(spConfig.getSmsNodeID(), // node id同上
spConfig.getSmsSpNumber(), // cp_phone
spConfig.getSmsCPNUMBER(), // 付費號碼
1, // 接收短消息的手機數
"86130xxxxxxx", // 手機號碼前面加86
spConfig.getSmsCPID(), // cp_id
"",// 業務代碼
0,// 計費類型
"500",// 短消息收費值
"500",// 贈送話費
1,// 代收標志
1,// 引起MT的原因
9,// 優先級
"",// 短消息終止時間
"",// 011125120000032+短消息定時發送時間
1,// 狀態報告標志
1,// GSM協議類型
1,// GSM協議類型
8,// 短消息編碼格式
0,// 信息類型
2,// 短消息長度,此處僅為了得到對象任意填入
new byte[]{0x00,0x00});//內容,任意填入
//該方法才真正寫入內容。
submit.setContent(8, new String (byte_content);
submit.write(out);// 發送submit
當然,最佳的方法是重寫Submit類的初始化方法,希望該開發包在下一版本推出時候已經解決了此問題。
二、關于編碼
通過String.getByte(String charsetName)方法以指定編碼格式產生字符串的byte數組,而String的構造方法String(byte[] bytes, String charsetName),可以將byte數組以指定的編碼格式解析為字符串。在這里采用iso-10646-ucs-2編碼方式:
String message="xxxx";//中英文混合字符串
byte[] messageUCS2 = message.getBytes("iso-10646-ucs-2");
byte[] tp_udhiHead = new byte[6];
tp_udhiHead[0] = 0x05;
tp_udhiHead[1] = 0x00;
tp_udhiHead[2] = 0x03;
tp_udhiHead[3] = 0x0A;
tp_udhiHead[4] = 0x02;// 共兩條短信
tp_udhiHead[5] = 0x01;// 默認為第一條
byte[] tp_udhiHead = byteAdd(tp_udhiHead,messageUCS2);//將messageUCS2加入到tp_udhiHead后面
String strContent=new String (tp_udhiHead,"ISO8859-1")
message和strContent(除去包頭部分)的內部編碼是一致的,這樣保證了發送的短信在用戶手機上不會因為內容部分增加了包頭而顯示亂碼。
小結如下:
1、在采用項目外部提供的公共類包時候,要有懷疑態度,不能想當然認為原程序作者已經實現了所有你要的功能,畢竟寫程序的是人,他也可能犯錯。
2、遇到亂碼問題,最好能將程序化繁為簡,并盡可能在測試平臺上多做測試,光憑想象有時候并不能很快解決問題,反而容易浪費時間。
3、在遇到問題時要和有經驗的人多討論,這有助于你找到解決問題方法,但是記住最終解決問題的,只有你自己,不能完全寄希望于他人。
一、關于spapi.jar短信發送包br /> 要讓用戶的手機能夠識別該短信是否是長短信,根據協議規定,應在內容字段中增加包頭:
































new byte[]{0x00,0x00});//內容,任意填入



二、關于編碼
通過String.getByte(String charsetName)方法以指定編碼格式產生字符串的byte數組,而String的構造方法String(byte[] bytes, String charsetName),可以將byte數組以指定的編碼格式解析為字符串。在這里采用iso-10646-ucs-2編碼方式:











小結如下:
1、在采用項目外部提供的公共類包時候,要有懷疑態度,不能想當然認為原程序作者已經實現了所有你要的功能,畢竟寫程序的是人,他也可能犯錯。
2、遇到亂碼問題,最好能將程序化繁為簡,并盡可能在測試平臺上多做測試,光憑想象有時候并不能很快解決問題,反而容易浪費時間。
3、在遇到問題時要和有經驗的人多討論,這有助于你找到解決問題方法,但是記住最終解決問題的,只有你自己,不能完全寄希望于他人。