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

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
































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



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











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