使用Java发送短信息的方式有两种:
1>使用第三方平台的http请求进行发送,优点是接口简单,使用方便,发送的效率高,多条可以同时发送,缺点是短信平台,三大运营商不提供接口,都是第三方平台,但是第三方平台不稳定,如果倒闭,将意味着这套代码请求的服务器倒闭,则代码失效,需要再找另外的第三方公司;
2>硬件设备,短信猫,比如深圳宏电的H6221GPRS Mode模块,优点是发送稳定,不会出现担心第三方平台倒闭而重写代码的风险,缺点是需要硬件,资费是正常的短信价格,一台设备同一时间只能发送一条信息,成本较高;
下面给出使用短信猫发信息的Java代码:
下载所需jar包
1,字符编码转换工具类:
package sms;
/**
* 短信发送字符编码工具类
* @author Anlw
*
*/
public class StringUtil {
/**
* 将PDU编码的十六进制字符串 如“4F60597DFF01” 转换成unicode "\u4F60\u597D\uFF01"
* @param str 要转化的字符串
* @return 转换后的十六进制字符串
*/
public static String analyseStr(String str) {
StringBuffer sb = new StringBuffer();
if (!(str.length() % 4 == 0))
return str;
for (int i = 0; i < str.length(); i++) {
if (i == 0 || i % 4 == 0) {
sb.append("\\u");
}
sb.append(str.charAt(i));
}
return Unicode2GBK(sb.toString());
}
/**
* 将unicode编码 "\u4F60\u597D\uFF01" 转换成中文 "你好!"
* @param dataStr 要转化的字符串
* @return 转换后的中文字符串
*/
public static String Unicode2GBK(String str) {
int index = 0;
StringBuffer buffer = new StringBuffer();
while (index < str.length()) {
if (!"\\u".equals(str.substring(index, index + 2))) {
buffer.append(str.charAt(index));
index++;
continue;
}
String charStr = "";
charStr = str.substring(index + 2, index + 6);
char letter = 0;
try{letter = (char) Integer.parseInt(charStr, 16);}catch (Exception e) {}
buffer.append(letter);
index += 6;
}
return buffer.toString();
}
/**
* 将中文字符串转换成Unicode
* @param str 要转换的中文字符串
* @return 转换后的Unicode
*/
public static String GBK2Unicode(String str) {
StringBuffer result = new StringBuffer();
for (int i = 0; i < str.length(); i++) {
char chr1 = (char) str.charAt(i);
if (!isNeedConvert(chr1)) {
result.append(chr1);
continue;
}
try{result.append("\\u" + Integer.toHexString((int) chr1));}catch (Exception e) {}
}
return result.toString();
}
/**
* 在中文字符串转换成Unicode方法中判断是否需要转换
* @param para 要转化的字符
* @return boolean
*/
public static boolean isNeedConvert(char para) {
return ((para & (0x00FF)) != para);
}
/**
* 使用Sms 的 SendSms()方法发送短信时,调用此方法将其短信内容转换成十六进制
* @param msg 短信内容
* @return 转换后的十六进制短信
*/
public static final String encodeHex(String str) {
byte[] bytes = null;
try {
bytes = str.getBytes("GBK");
} catch (java.io.UnsupportedEncodingException e) {
e.printStackTrace();
}
StringBuffer buff = new StringBuffer(bytes.length * 4);
String b = "";
char a;
int n = 0;
int m = 0;
for (int i = 0; i < bytes.length; i++) {
try{b = Integer.toHexString(bytes[i]);}catch (Exception e) {}
if (bytes[i] > 0) {
buff.append("00");
buff.append(b);
n = n + 1;
} else {
a = str.charAt((i - n) / 2 + n);
m = a;
try{b = Integer.toHexString(m);}catch (Exception e) {}
buff.append(b.substring(0, 4));
i = i + 1;
}
}
return buff.toString();
}
}
2,端口实体类,包括操作端口的方法:
package sms;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Random;
import javax.comm.CommPortIdentifier;
import javax.comm.NoSuchPortException;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.UnsupportedCommOperationException;
/**
* 串口操作实现类
* @author Anlw
*
*/
public class Port {
private CommPortIdentifier portId;
private SerialPort serialPort;
private OutputStreamWriter out;
private InputStreamReader in;
private String COMname;
public String getCOMname() {
return COMname;
}
public void setCOMname(String mname) {
COMname = mname;
}
public CommPortIdentifier getPortId() {
return portId;
}
public void setPortId(CommPortIdentifier portId) {
this.portId = portId;
}
public SerialPort getSerialPort() {
return serialPort;
}
public void setSerialPort(SerialPort serialPort) {
this.serialPort = serialPort;
}
public OutputStreamWriter getOut() {
return out;
}
public void setOut(OutputStreamWriter out) {
this.out = out;
}
public InputStreamReader getIn() {
return in;
}
public void setIn(InputStreamReader in) {
this.in = in;
}
public boolean isused = true;
public boolean isIsused() {
return isused;
}
public void setIsused(boolean isused) {
this.isused = isused;
}
/**
* 构造器打开com口
* @param portName
* @return
*/
public Port(String portName) {
try {
portId = CommPortIdentifier.getPortIdentifier(portName);
if (portId == null) {
System.out.println("port is null");
}
try {
serialPort = (SerialPort) portId.open(getrechargeablePassword(), 20000);
} catch (PortInUseException e) {
System.gc();
System.out.println("COM端口被占用,请选择正确的COM端口!!");
}
// 下面是得到用于和COM口通讯的输入、输出流。
try {
in = new InputStreamReader(serialPort.getInputStream());
out = new OutputStreamWriter(serialPort.getOutputStream());
} catch (Exception e) {
System.gc();
}
// 下面是初始化COM口的传输参数,如传输速率:9600等
try {
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
setCOMname(portId.getName());
setIsused(true);
} catch (Exception e) {
System.gc();
}
} catch (NoSuchPortException e) {
System.gc();
System.out.println("无此COM端口,请选择正确的COM端口!!");
}
}
// 获取密码
public static String getrechargeablePassword() {
Random random = new Random();
char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'c',
'b', 'd', 'f', 'e', 'g', 'h', 'j', 'i', 'l', 'k', 'n', 'm', 'o', 'p', 'q', 'r', 's', 't', 'u', 'w',
'v' };
String strRand = "";
for (int i = 0; i < 18; i++) {
strRand = strRand + String.valueOf(codeSequence[random.nextInt(59)]);
}
return strRand;
}
/**
* 关闭COM口
* @return boolean
*/
public void close() {
try {
in.close();
out.close();
serialPort.close();
System.gc();
setIsused(false);
} catch (Exception e) {
}
}
/**
* 向串口中写入字符串命令
* @param s 字符串命令
* @throws Exception 异常
*/
public void writeln(String s) throws Exception {
out.write(s);
out.write('\r');
out.flush();
}
/**
* 读取COM命令的返回字符串
* @return 结果字符串
* @throws Exception
*/
public String read() throws Exception {
int n, i;
char c;
String answer = "";
for (i = 0; i < 100; i++) {
while (in.ready()) {
n = in.read();
if (n != -1) {
c = (char) n;
answer = answer + c;
Thread.sleep(1);
} else
break;
}
if (answer.indexOf("OK") != -1) {
break;
}
Thread.sleep(100);
}
return answer;
}
/**
* 向串口发送AT指令
* @param atcommand 指令内容
* @return 指令返回结果
* @throws java.rmi.RemoteException
*/
public String sendAT(String atcommand) throws java.rmi.RemoteException {
String returnStr = "";
try {
Thread.sleep(100);
writeln(atcommand);
Thread.sleep(80);
returnStr = read();
Thread.sleep(150);
} catch (Exception e) {
System.gc();
}
return returnStr;
}
}
3,短信息载体实体类:
package sms;
/**
* 短信实体类
* @author Anlw
*
*/
public class CommonSms{
//内容
private String smstext;
//发送者
private String sender;
//接收者
private String recver;
//状态
private String state;
public String getSmstext() {
return smstext;
}
public void setSmstext(String smstext) {
this.smstext = smstext;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getRecver() {
return recver;
}
public void setRecver(String recver) {
this.recver = recver;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
4,发送核心代码:
package sms;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.comm.CommPortIdentifier;
/**
* 短信息发送
* @author Anlw
*
*/
public class Sms {
private CommonSms commonsms;
private static char symbol1 = 13;
private static String strReturn = "", atCommand = "";
private boolean SendSms(Port myport) {
if (!myport.isIsused()) {
System.out.println("COM通讯端口未正常打开!");
return false;
}
setMessageMode(myport, 1);
// 空格
char symbol2 = 34;
// ctrl~z 发送指令
char symbol3 = 26;
try {
atCommand = "AT+CSMP=17,169,0,08" + String.valueOf(symbol1);
strReturn = myport.sendAT(atCommand);
if (strReturn.indexOf("OK", 0) != -1) {
atCommand = "AT+CMGS=" + commonsms.getRecver() + String.valueOf(symbol1);
strReturn = myport.sendAT(atCommand);
atCommand = StringUtil.encodeHex(commonsms.getSmstext().trim()) + String.valueOf(symbol3)
+ String.valueOf(symbol1);
strReturn = myport.sendAT(atCommand);
if (strReturn.indexOf("OK") != -1 && strReturn.indexOf("+CMGS") != -1) {
System.out.println("短信发送成功!!");
return true;
}
}
} catch (Exception ex) {
System.out.println("短信发送失败!!");
return false;
}
System.out.println("COM端口被占用,请选择正确的COM端口!!");
System.out.println("短信发送失败!!");
return false;
}
/**
* 设置消息模式
* @param op
* 0-pdu 1-text(默认1 文本方式 )
* @return
*/
private boolean setMessageMode(Port myport, int op) {
try {
String atCommand = "AT+CMGF=" + String.valueOf(op) + String.valueOf(symbol1);
String strReturn = myport.sendAT(atCommand);
if (strReturn.indexOf("OK", 0) != -1) {
return true;
}
return false;
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
/**
* 号码,内容,发送短信息
* @param phone
* @param countstring
* @throws Exception
*/
private static void send(String phone, String countstring, String com) {
Sms s = new Sms();
CommonSms cs = new CommonSms();
cs.setRecver(phone);
cs.setSmstext(countstring);
s.setCommonsms(cs);
Port myort = new Port(com);
s.SendSms(myort);
myort.close();
}
//短信的字符限制为70,加锁,因为每次只能发送一条,其他的要等待
public static synchronized void sendSms(String phone, String str, String com) {
if (str.length() > 70) {
String done = str.substring(0, 70);
Sms.send(phone, done, com);
String todo = str.substring(70, str.length());
Sms.sendSms(phone, todo, com);
} else {
Sms.send(phone, str, com);
}
}
private void setCommonsms(CommonSms commonsms) {
this.commonsms = commonsms;
}
//获取计算机所有可用端口
public static List getComPort() {
Enumeration enumeration = CommPortIdentifier.getPortIdentifiers();
CommPortIdentifier portId;
List list = new ArrayList();
while (enumeration.hasMoreElements()) {
portId = (CommPortIdentifier) enumeration.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
list.add(portId.getName());
}
}
return list;
}
}
5,测试类:
package sms;
public class Test {
public static void main(String[] args) {
final String str1 = "嘿嘿";
final String str2 = "嘻嘻";
Sms.sendSms("13311220311", "str1heihei", "COM6");
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// Sms.sendSms("13311220311", str1, "COM6");
// }
// }).start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// Sms.sendSms("13311220311", str2, "COM6");
// }
// }).start();
}
}